Request for update – Does this still work the same in Rails 1.0.0? Or does save automatically update the collections?
Suppose you have a schema like:
CREATE TABLE users (
id INTEGER PRIMARY KEY,
login VARCHAR(80) DEFAULT NULL,
password VARCHAR(40) DEFAULT NULL
);
CREATE TABLE user_emails (
user_id INTEGER NOT NULL,
address VARCHAR(80)
);
Naturally, a User object has_many \UserEmail objects, so user.user_emails gets you an array of them. Great.
However, the users controller doesn’t know about the user_emails. For the list or show actions, it’s pretty easy to just show them in the view. But for create or update, I’m not sure what I’m supposed to do. The default scaffold code gives me:
@user = User.find(@params[:id])
if @user.update_attributes(@params[:user])
...
How do I modify this to update @user.user_emails ? Or, am I going about this in the wrong way? Any advice is most welcome!
MikkelBruun: adding an useremail object to the user??
user.user:emails<<email
if you are editing an email you dont have to update the user…Am I missing your point here??
DanMills?: Well, I want to edit the user’s email addresses on the same form I use to edit the user itself. So I add fields to views/user/edit.rhtml for this. But I’m wondering if there’s some simple method, like ”@object.update_attributes” that I can use when I have an array like “user.user_emails”.
Does that make sense? Maybe I’m just looking at this in the wrong way…
MikkelBruun Oh Yeah…those relations you have to manage by hand…I dont think there’s any easy way around this…
Julik: Rails 0.13 (more specifically, the new version of ActiveRecord) autm-generates the assignment accessors for collections, so you can just do
item.subitems = Subitem.find(:all)
SteveErickson?: Dan, I’m experiencing the exact same problem. I know how to do this manually, but I keep feeling like there has got to be some “clean” way that Rails does this. I think you’d agree.
JasonGarber?: The solution is simple, as it should be with Rails. Pardon me for changing the example objects from the question above. I’ll adapt the code to users and e-mail addresses someday when I have time.
<% @person.sections.each do |@section| %>
<%= text_field "section[]", "section_title" %>
<%= text_area "section[]", "section_content" %>
<% end %>
def update
@person = Person.find(@params[:id])
update_result = @person.update_attributes(@params[:person])
@person.sections.collect do |section|
update_result &&= section.update_attributes(@params[:section][section.id.to_s])
end
if update_result
flash[:notice] = 'Person was successfully updated.'
redirect_to :action => 'show', :id => @person
else
render :action => 'edit'
end
end
update_result is used to make sure all parts of the update are successful
You can also integrate adding and deleting of sections with AJAX as I have (not shown)
You might like to wrap a transaction.do around that too. You wouldn’t want one child being updated while others aren’t. —AnonymousCoward
“LG”: Ok – That works! I just tried it. But can someone explain why it works? It is kind of a mystery why we should sort of ‘cast’ section as an array in the view and use it as such in the controller. Maybe I don’t understand the ‘collect’ method, and I’m thinking of it like ‘each’.
How come ‘each’ doesn’t work here? – LG
REQUEST: Can someone please do ‘create’ example? I can’t seem to get the parent_id to the child’s foreign key. This is when I’m creating the parent and child(ren) at the same time
Request: In the above examples, user.user_emails, or person.sections, how can I get updated_at to automatically update its timestamp whenever user_emails or sections are changed with additions or removals?
category:Howto
I ran into a similar problem, where you want to use update_attributes but one of the attributes you’re updating is a belongs_to, e.g. Player belongs_to Team, and you’re updating Player. By default with a scaffold you’ll get an error like “Expected Team but got String”. update_attributes is trying to set Player.Team to a Team object but
params[:player][:team] is an id String. What I do in my controller then is add this statement just before the update_attributes statement:
params[:player][:team] = Team.find(params[:player][:team])
This works, but I’d be interested in anyone’s opinion on whether this is a bad practice for some reason.
Request for update – Does this still work the same in Rails 1.0.0? Or does save automatically update the collections?
Suppose you have a schema like:
CREATE TABLE users (
id INTEGER PRIMARY KEY,
login VARCHAR(80) DEFAULT NULL,
password VARCHAR(40) DEFAULT NULL
);
CREATE TABLE user_emails (
user_id INTEGER NOT NULL,
address VARCHAR(80)
);
Naturally, a User object has_many \UserEmail objects, so user.user_emails gets you an array of them. Great.
However, the users controller doesn’t know about the user_emails. For the list or show actions, it’s pretty easy to just show them in the view. But for create or update, I’m not sure what I’m supposed to do. The default scaffold code gives me:
@user = User.find(@params[:id])
if @user.update_attributes(@params[:user])
...
How do I modify this to update @user.user_emails ? Or, am I going about this in the wrong way? Any advice is most welcome!
MikkelBruun: adding an useremail object to the user??
user.user:emails<<email
if you are editing an email you dont have to update the user…Am I missing your point here??
DanMills?: Well, I want to edit the user’s email addresses on the same form I use to edit the user itself. So I add fields to views/user/edit.rhtml for this. But I’m wondering if there’s some simple method, like ”@object.update_attributes” that I can use when I have an array like “user.user_emails”.
Does that make sense? Maybe I’m just looking at this in the wrong way…
MikkelBruun Oh Yeah…those relations you have to manage by hand…I dont think there’s any easy way around this…
Julik: Rails 0.13 (more specifically, the new version of ActiveRecord) autm-generates the assignment accessors for collections, so you can just do
item.subitems = Subitem.find(:all)
SteveErickson?: Dan, I’m experiencing the exact same problem. I know how to do this manually, but I keep feeling like there has got to be some “clean” way that Rails does this. I think you’d agree.
JasonGarber?: The solution is simple, as it should be with Rails. Pardon me for changing the example objects from the question above. I’ll adapt the code to users and e-mail addresses someday when I have time.
<% @person.sections.each do |@section| %>
<%= text_field "section[]", "section_title" %>
<%= text_area "section[]", "section_content" %>
<% end %>
def update
@person = Person.find(@params[:id])
update_result = @person.update_attributes(@params[:person])
@person.sections.collect do |section|
update_result &&= section.update_attributes(@params[:section][section.id.to_s])
end
if update_result
flash[:notice] = 'Person was successfully updated.'
redirect_to :action => 'show', :id => @person
else
render :action => 'edit'
end
end
update_result is used to make sure all parts of the update are successful
You can also integrate adding and deleting of sections with AJAX as I have (not shown)
You might like to wrap a transaction.do around that too. You wouldn’t want one child being updated while others aren’t. —AnonymousCoward
“LG”: Ok – That works! I just tried it. But can someone explain why it works? It is kind of a mystery why we should sort of ‘cast’ section as an array in the view and use it as such in the controller. Maybe I don’t understand the ‘collect’ method, and I’m thinking of it like ‘each’.
How come ‘each’ doesn’t work here? – LG
REQUEST: Can someone please do ‘create’ example? I can’t seem to get the parent_id to the child’s foreign key. This is when I’m creating the parent and child(ren) at the same time
Request: In the above examples, user.user_emails, or person.sections, how can I get updated_at to automatically update its timestamp whenever user_emails or sections are changed with additions or removals?
category:Howto
I ran into a similar problem, where you want to use update_attributes but one of the attributes you’re updating is a belongs_to, e.g. Player belongs_to Team, and you’re updating Player. By default with a scaffold you’ll get an error like “Expected Team but got String”. update_attributes is trying to set Player.Team to a Team object but
params[:player][:team] is an id String. What I do in my controller then is add this statement just before the update_attributes statement:
params[:player][:team] = Team.find(params[:player][:team])
This works, but I’d be interested in anyone’s opinion on whether this is a bad practice for some reason.