Hi all, I have a rather weird problem. Three models in has_many :through relationship: Nutrient <-- IngredientsNutrient --> Ingredient Nutrient has_many :ingredient_nutrients Nutrient has_many Ingredients, :through => :ingredient_nutrients Ingredient has_many :ingredient_nutrients Ingredient has_many :nutrients, :through => :ingredient_nutrients IngredientsNutrient belongs_to :nutrient IngredientsNutrient belongs_to :ingredient IngredientsNutrient is a model, because I need to specify the quantity of nutrients per ingredient. With this, I wanted to create a form for Ingredient model which includes IngredientsNutrient fields for each Nutrient.all. I''ve added to Ingredient: accepts_nested_attributes_for :ingredients_nutrient and went on to add in the view: <% f.fields_for :ingredients_nutrient do |in_f| %> .... <% end %> In the controller, I have the following code: for nutrient in Nutrient.all @ingredient.ingredients_nutrients.build({ :nutrient_id => nutrient.id }) end When I submit the form filling out all the fields, it fails validation saying that ingredient_id cannot be blank (exact message is: "Ingredient nutrients ingredient can''t be blank"). My initial assumption was that the ingredient_id needs not be specified, but either Rails doesn''t think so, or I have made an error in coding. I''ve double checked Ryan''s examples of nested attributes, but I can''t see anything. The only thing I''ve noticed that he didn''t deal with has_many-through type of relationship. Can anyone please point me in the right direction? Thanks, -- Branko
I don''t know whether this is part of the problem or just that your question has several typos. I think the class should be IngredientNutrient not IngredientsNutrient and the controller should be ingredient_nutrients. You have them in various combinations throughout the post. Colin 2009/5/15 Branko Vukelic <bg.branko-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>> > Hi all, > > I have a rather weird problem. Three models in has_many :through > relationship: > > Nutrient <-- IngredientsNutrient --> Ingredient > > Nutrient has_many :ingredient_nutrients > Nutrient has_many Ingredients, :through => :ingredient_nutrients > Ingredient has_many :ingredient_nutrients > Ingredient has_many :nutrients, :through => :ingredient_nutrients > IngredientsNutrient belongs_to :nutrient > IngredientsNutrient belongs_to :ingredient > > IngredientsNutrient is a model, because I need to specify the quantity > of nutrients per ingredient. > > With this, I wanted to create a form for Ingredient model which > includes IngredientsNutrient fields for each Nutrient.all. > > I''ve added to Ingredient: > > accepts_nested_attributes_for :ingredients_nutrient > > and went on to add in the view: > > <% f.fields_for :ingredients_nutrient do |in_f| %> > .... > <% end %> > > In the controller, I have the following code: > > for nutrient in Nutrient.all > @ingredient.ingredients_nutrients.build({ :nutrient_id => > nutrient.id }) > end > > When I submit the form filling out all the fields, it fails validation > saying that ingredient_id cannot be blank (exact message is: > "Ingredient nutrients ingredient can''t be blank"). > > My initial assumption was that the ingredient_id needs not be > specified, but either Rails doesn''t think so, or I have made an error > in coding. I''ve double checked Ryan''s examples of nested attributes, > but I can''t see anything. The only thing I''ve noticed that he didn''t > deal with has_many-through type of relationship. > > Can anyone please point me in the right direction? > > Thanks, > > -- > Branko > > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On May 15, 4:02 pm, Colin Law <clan...-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org> wrote:> I don''t know whether this is part of the problem or just that your question > has several typos. > > I think the class should be IngredientNutrient not IngredientsNutrient and > the controller should be ingredient_nutrients. You have them in various > combinations throughout the post.Thanks, Colin. I''ll try IngredientNutrient. Could be that *that''s* the reason it''s not working.
On May 15, 6:47 pm, Branko Vukelic <bg.bra...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> On May 15, 4:02 pm, Colin Law <clan...-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org> wrote: > > > I don''t know whether this is part of the problem or just that your question > > has several typos. > > > I think the class should be IngredientNutrient not IngredientsNutrient and > > the controller should be ingredient_nutrients. You have them in various > > combinations throughout the post. > > Thanks, Colin. I''ll try IngredientNutrient. Could be that *that''s* the > reason it''s not working.It makes no difference, but then again, it''s logical. No matter how incredibly stupid a model''s name is, if you use it consistently (which I did in live code) it works the same way as a smart name. :P I''m really not sure what''s going on...
Can anyone else help here, I haven''t used nested attributes yet. 2009/5/15 Branko Vukelic <bg.branko-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>> > On May 15, 6:47 pm, Branko Vukelic <bg.bra...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > On May 15, 4:02 pm, Colin Law <clan...-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org> wrote: > > > > > I don''t know whether this is part of the problem or just that your > question > > > has several typos. > > > > > I think the class should be IngredientNutrient not IngredientsNutrient > and > > > the controller should be ingredient_nutrients. You have them in various > > > combinations throughout the post. > > > > Thanks, Colin. I''ll try IngredientNutrient. Could be that *that''s* the > > reason it''s not working. > > It makes no difference, but then again, it''s logical. No matter how > incredibly stupid a model''s name is, if you use it consistently (which > I did in live code) it works the same way as a smart name. :P > > I''m really not sure what''s going on... > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On May 15, 7:29 pm, Colin Law <clan...-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org> wrote:> Can anyone else help here, I haven''t used nested attributes yet.Can''t find a single example using has_many-through. Is there any other way to get multi-model forms work for my setup?
On Friday 15 May 2009, Branko Vukelic wrote:> On May 15, 7:29 pm, Colin Law <clan...-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org> wrote: > > Can anyone else help here, I haven''t used nested attributes yet. > > Can''t find a single example using has_many-through. Is there any > other way to get multi-model forms work for my setup?I haven''t looked into your problem in depth, but class Ingredient < ... accepts_nested_attributes_for :ingredient_nutrient end doesn''t help, because you''re not *creating* ingredients with associated ingredient_nutrients. Rather, you''re associating existing ingredients and nutrients with the help of ingredient_nutrients. I think in order to get better help you ought to post more of your code and the exact exception messages you get. Michael -- Michael Schuerig mailto:michael-q5aiKMLteq4b1SvskN2V4Q@public.gmane.org http://www.schuerig.de/michael/
On May 15, 9:20 pm, Michael Schuerig <mich...-q5aiKMLteq4b1SvskN2V4Q@public.gmane.org> wrote:> doesn''t help, because you''re not *creating* ingredients with associated > ingredient_nutrients. Rather, you''re associating existing ingredients > and nutrients with the help of ingredient_nutrients.I''m starting to think this might be a design problem... Back to square 1, what I''m trying to do is the following: I have a bunch of _nutrients_ which are defined by their `name` and the `units` used to measure them. I have _ingredients_ that are defined by their `name`, and some meta data irrelevant for this setup. Finally I wish to be able to enter the ingredients and associated nutritional information (i.e., the nutrients and their quantities) in one go. The initial plan was to have all nutrients as columns in the ingredients table, but then we realized that the number of nutrients may change from time to time, and that''s why I opted for the above setup. Here''s the model code that I''m using right now (renamed the awkward "IngredientNutrient" to "Nutrition"): class Ingredient < ActiveRecord::Base has_many :nutritions has_many :nutrients, :through => :nutritions accepts_nested_attributes_for :nutritions validates_presence_of :name, :kind, :density validates_uniqueness_of :name validates_length_of :name, :maximum => 40 validates_inclusion_of :kind, :in => [0, 1, 2] end class Nutrient < ActiveRecord::Base has_many :nutritions has_many :ingredients, :through => :nutritions validates_presence_of :name, :unit validates_uniqueness_of :name validates_length_of :name, :maximum => 40 validates_inclusion_of :unit, :in => %w( g mg mcg IU ml ) end class Nutrition < ActiveRecord::Base belongs_to :nutrient belongs_to :ingredient validates_presence_of :nutrient_id, :ingredient_id, :quantity end The snippet from the Ingredients controller: def new @ingredient = Ingredient.new for nutrient in Nutrient.all @ingredient.nutritions.build :nutrient_id => nutrient.id # <-- this is probably bad? end .... end And finally the _form partial: <p> <%= f.label :name %><br /> <%= f.text_field :name %> </p> <p> <%= f.label :kind %><br /> <%= f.text_field :kind %> </p> <p> <%= f.label :density %><br /> <%= f.text_field :density %> </p> <p> <%= f.label :comments %><br /> <%= f.text_area :comments %> </p> <% f.fields_for :nutritions do |n_f| %> <p> <%= n_f.hidden_field :nutrient_id %> <%= n_f.text_field :quantity %> </p> <% end %> -- Branko
On Friday 15 May 2009, Branko Vukelic wrote:> On May 15, 9:20 pm, Michael Schuerig <mich...-q5aiKMLteq4b1SvskN2V4Q@public.gmane.org> wrote: > > doesn''t help, because you''re not *creating* ingredients with > > associated ingredient_nutrients. Rather, you''re associating > > existing ingredients and nutrients with the help of > > ingredient_nutrients. > > I''m starting to think this might be a design problem... > > Back to square 1, what I''m trying to do is the following: > > I have a bunch of _nutrients_ which are defined by their `name` and > the `units` used to measure them. I have _ingredients_ that are > defined by their `name`, and some meta data irrelevant for this > setup. Finally I wish to be able to enter the ingredients and > associated nutritional information (i.e., the nutrients and their > quantities) in one go.You''re not saying what doesn''t work with your code as it is.> The snippet from the Ingredients controller: > > def new > @ingredient = Ingredient.new > for nutrient in Nutrient.all > @ingredient.nutritions.build :nutrient_id => nutrient.id # > <-- this is probably bad?You could just write @ingredient.nutritions.build(:nutrient => nutrient) Michael -- Michael Schuerig mailto:michael-q5aiKMLteq4b1SvskN2V4Q@public.gmane.org http://www.schuerig.de/michael/
On May 16, 2:42 am, Michael Schuerig <mich...-q5aiKMLteq4b1SvskN2V4Q@public.gmane.org> wrote:> > The snippet from the Ingredients controller: > > > def new > > @ingredient = Ingredient.new > > for nutrient in Nutrient.all > > @ingredient.nutritions.build :nutrient_id => nutrient.id # > > <-- this is probably bad? > > You could just write > > @ingredient.nutritions.build(:nutrient => nutrient)Got it. But that doesn''t solve the problem, does it? Btw, the error message displayed by the form is "Nutrients ingredient can''t be blank".
On Saturday 16 May 2009, Branko Vukelic wrote:> Btw, the error message displayed by the form is "Nutrients ingredient > can''t be blank".You know, this is a bit like pulling teeth. When are you getting this message? Presumably you''re trying to save something. What objects are there? Which of them are new and unsaved (new_record? == true), which of them already exist in the database (new_record? == false), but need saving, which are unchanged. Finally, how are you saving them. I can''t point to any specific problem, but I suspect you''re running into non-intuitive issues related to when objects and their associated objects are saved, in particular, if there are new objects in the mix. The API docs as well as Agile Web Dev with Rails have sections on this topic, it might be a good idea to review them. This is just a hunch, the cause of your problem may be somewhere else entirely. Michael -- Michael Schuerig mailto:michael-q5aiKMLteq4b1SvskN2V4Q@public.gmane.org http://www.schuerig.de/michael/
On May 16, 12:26 pm, Michael Schuerig <mich...-q5aiKMLteq4b1SvskN2V4Q@public.gmane.org> wrote:> On Saturday 16 May 2009, Branko Vukelic wrote: > > > Btw, the error message displayed by the form is "Nutrients ingredient > > can''t be blank". > > You know, this is a bit like pulling teeth. When are you getting thisOuch. Sorry, I''m sort of new to Rails, so I don''t know what messages I can acquire, and where to look for them.> message? Presumably you''re trying to save something. What objects are > there? Which of them are new and unsaved (new_record? == true), which of > them already exist in the database (new_record? == false), but need > saving, which are unchanged. Finally, how are you saving them.I have a blank database. Then I create 2 Nutrient objects so the forms for Nutritions (the join model) appear as expected. Two text boxes accompanied by two hidden fields. All other objects I''m trying to create (1 x Ingredient + 2 x Nutritions) are new.> I can''t point to any specific problem, but I suspect you''re running into > non-intuitive issues related to when objects and their associated > objects are saved, in particular, if there are new objects in the mix. > The API docs as well as Agile Web Dev with Rails have sections on this > topic, it might be a good idea to review them. This is just a hunch, the > cause of your problem may be somewhere else entirely.Well, I''m definitely not familiar with how Rails internally handles the order of creation of new objects when using has_many-through and a mixed-model form with all new objects... and many other things. :P What particular section of API docs should I be reading? Thanks for help, all. -- Branko
On Saturday 16 May 2009, Branko Vukelic wrote:> > I can''t point to any specific problem, but I suspect you''re running > > into non-intuitive issues related to when objects and their > > associated objects are saved, in particular, if there are new > > objects in the mix. The API docs as well as Agile Web Dev with > > Rails have sections on this topic, it might be a good idea to > > review them. This is just a hunch, the cause of your problem may be > > somewhere else entirely. > > Well, I''m definitely not familiar with how Rails internally handles > the order of creation of new objects when using has_many-through and > a mixed-model form with all new objects... and many other things. :P > > What particular section of API docs should I be reading?http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html Look for "Unsaved objects and associations" If you don''t know this stuff yet (or, like me, keep forgetting the details), it is a very good idea to read up on it every now and then, even if it isn''t necessarily responsible for your current problem. Michael -- Michael Schuerig mailto:michael-q5aiKMLteq4b1SvskN2V4Q@public.gmane.org http://www.schuerig.de/michael/
On May 16, 10:14 pm, Michael Schuerig <mich...-q5aiKMLteq4b1SvskN2V4Q@public.gmane.org> wrote:> http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMet... > Look for "Unsaved objects and associations" > > If you don''t know this stuff yet (or, like me, keep forgetting the > details), it is a very good idea to read up on it every now and then, > even if it isn''t necessarily responsible for your current problem.Thanks for the link. Meanwhile, I suspect the problem is not (just) the unsaved objects. Judging from the error message, I''ve a feeling that with my setup Rails is having problems realizing that the nested attributes are for objects related to the object being created by the rest of the form. -- Branko
Here''s the request that triggers the error: Parameters: { "commit"=>"Create", "authenticity_token"=>"4UoqTR94w4Nf8LcNwgeqFfUDm7fZ +UvYeQDrfrflolw=", "ingredient"=>{ "kind"=>"1", "name"=>"test", "comments"=>"", "nutritions_attributes"=>{ "0"=>{ "quantity"=>"123", "nutrient_id"=>"1" } }, "density"=>"123"} } So the accepts_nested_attributes_for is obviously not doing what I thought it does (which is, create associated objects from `objectname_attributes` params)... -- Branko
Ok, it''s becoming a bit clearer to me now.>> a = Ingredient.new=> #<Ingredient id: nil, name: nil, kind: nil, density: nil, comments: nil, weight_per_piece: nil>>> a.nutritions_attributes = [{ :nutrient_id => 1, :quantity => 123 }]=> [{:nutrient_id=>1, :quantity=>123}]>> a.name = ''test''=> "test">> a.kind = 1=> 1>> a.density = 2=> 2>> a.valid?=> false>> a.errors=> #<ActiveRecord::Errors:0xb72b5e78 @errors{"nutritions_ingredient_id"=>["can''t be blank"]}, @base=#<Ingredient id: nil, name: "test", kind: 1, density: #<BigDecimal:b72a56cc,''0.2E1'', 4(8)>, comments: nil, weight_per_piece: nil>> I can save the Ingredient instance while no Nutrition instances are attached to it (which makes heck of a lot of sense)... -- Branko
I carefully read all the comments on Ryan''s Scraps.[1] A similar issue filed as a ticked on lighthouse[2] is marked as ''wontfix'', so I assume it has nothing to do with nested_attributes, but with how Rails work in general. I''m still having trouble figuring out why and how, but it seems I''m not alone[3]... which kinda sucks... :( 1: http://ryandaigle.com/articles/2009/2/1/what-s-new-in-edge-rails-nested-attributes 2: https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/1943 3: http://railsforum.com/viewtopic.php?pid=96990 -- Branko
I decided to remove the validates_presence_of :nutrient_id, :ingredient_id from the Nutrition''s validation. And this works.To make sure I can''t save a blank _id field, I''ll add :allow_null => false to references columns. (I didn''t do it before because I didn''t know it was possible :P ). -- Branko
On Saturday 16 May 2009, Branko Vukelic wrote:> I decided to remove the > > validates_presence_of :nutrient_id, :ingredient_id > > from the Nutrition''s validation. And this works.To make sure I can''t > save a blank _id field, I''ll add :allow_null => false to references > columns. (I didn''t do it before because I didn''t know it was > possible :P ).Yes, probably your best bet in cases like this is to ensure consistency at the database level (you should do this anyway) and wrap a transaction block around the database manipulations. It may help to create/update objects piecemeal instead of trying to build a graph of objects and save them with a single object.save. Michael -- Michael Schuerig mailto:michael-q5aiKMLteq4b1SvskN2V4Q@public.gmane.org http://www.schuerig.de/michael/
On May 17, 12:59 am, Michael Schuerig <mich...-q5aiKMLteq4b1SvskN2V4Q@public.gmane.org> wrote:> On Saturday 16 May 2009, Branko Vukelic wrote: > > > I decided to remove the > > > validates_presence_of :nutrient_id, :ingredient_id > > > from the Nutrition''s validation. And this works.To make sure I can''t > > save a blank _id field, I''ll add :allow_null => false to references > > columns. (I didn''t do it before because I didn''t know it was > > possible :P ). > > Yes, probably your best bet in cases like this is to ensure consistency > at the database level (you should do this anyway) and wrap a transaction > block around the database manipulations. It may help to create/update > objects piecemeal instead of trying to build a graph of objects and save > them with a single object.save.I wanted to keep the controllers as clean as possible. In this case, it makes a lot of sense to have the nutrients entered from the ingredients page. So, the only options I had left were to add a new method to the Ingredient model (possibly after_save callback?), or do it the way I did... The other option seemed like a more elegant solution probably because I''m coming from Django with those inline admin forms goodness. :))) -- Branko