Hi,
I am trying to use the update_attributes on object with nested
attributes and I am getting the following error:
ProductPrice expected, got HashWithIndifferentAccess
Here''s the situation (simplified):
class Product < ActiveRecord::Base
belongs_to :productPrice
end
class ProductPrice < ActiveRecord::Base
has_one :product,
:dependent => true
validates_presence_of :costprice, :listprice
end
my parameters look something like this:
params = {
:product => {
:productno => "something",
:description => "something else",
:productPrice => {
:costprice => 30.34,
:listprice => 4.45
}
}
}
I get the error when I run product.update_attributes(params[:product])
Can anybody give me a hint on how to work with nested attributes?
Thanks
Peter
Peter Bohm wrote:> I am trying to use the update_attributes on object with nested > attributes and I am getting the following error: > > ProductPrice expected, got HashWithIndifferentAccess > > Here''s the situation (simplified): > > class Product < ActiveRecord::Base > belongs_to :productPrice > end > > class ProductPrice < ActiveRecord::Base > has_one :product, > :dependent => true > > validates_presence_of :costprice, :listprice > > end > > my parameters look something like this: > params = { > :product => { > :productno => "something", > :description => "something else", > :productPrice => { > :costprice => 30.34, > :listprice => 4.45 > } > } > }This''d probably work: params[:product][:productPrice] = ProductPrice.new( params[:product][:productPrice] ) product.update_attributes( params[:product] ) or product.build_product_price( params[:product][:productPrice] ) params[:product].delete( :productPrice ) product.update_attributes( params[:product] ) Though: 1. You should use underscore format for your belongs_to (belongs_to :product_price) 2. If you nest the names in your form the form helpers aren''t going to auto fill form values unless you use the form helper compound objects patch. So it''d probably be nicer not to nest the parameters and do: product.build_product_price( params[:product_price] ) product.update_attributes( params[:product] ) -- We develop, watch us RoR, in numbers too big to ignore.
I assume that you have the correct database schema to match the attributes? Also, but I don''t know if there is any difference, try: product.attributes params[:product] If the latter fails, can you reply with your DB schema/sql statements? Cheers Nic
Hi Mark,
thank you very much for answer
the camel case was just the typo - anyway, thanks for pointing out
As for the rest...
how I''ve been doing it is very similiar to what you suggested:
product.product_price.update_attributes(params[:product_price])
product.update_attributes(params[:product])
I don''t use build_product_price because I am not able to use it with
single table inheritance - e.g. ProductPrice is a "base class" and
it''s
extended by NetPrice, MarkupPrice, MarkdownPrice, etc. How do I pass the
actual implementation (class type) to the build_xxx method?
Anyways, why I brought the whole thing up is because it''s kind of
awkward to have another instance variable for nesting. There is a hint
of this in the agile book (table on p. 343) where the last row uses
user[address][city]=Wien for form parameters. That is translated to
{:user => {:address => {:city ="Wien"}}} and then used as
user.update_attributes(params[:user]).
However, I was neither able to get the form helpers to produce the
nested field nor use the update_attributes :-)
Thanks for help
Peter
Mark Reginald James wrote:
> Peter Bohm wrote:
>
>> I am trying to use the update_attributes on object with nested
>> attributes and I am getting the following error:
>>
>> ProductPrice expected, got HashWithIndifferentAccess
>>
>> Here''s the situation (simplified):
>>
>> class Product < ActiveRecord::Base
>> belongs_to :productPrice
>> end
>>
>> class ProductPrice < ActiveRecord::Base
>> has_one :product,
>> :dependent => true
>> validates_presence_of :costprice, :listprice
>> end
>>
>> my parameters look something like this:
>> params = {
>> :product => {
>> :productno => "something",
>> :description => "something else",
>> :productPrice => {
>> :costprice => 30.34,
>> :listprice => 4.45
>> }
>> }
>> }
>
>
> This''d probably work:
>
> params[:product][:productPrice] = ProductPrice.new(
> params[:product][:productPrice] )
> product.update_attributes( params[:product] )
>
> or
>
> product.build_product_price( params[:product][:productPrice] )
> params[:product].delete( :productPrice )
> product.update_attributes( params[:product] )
>
> Though:
>
> 1. You should use underscore format for your belongs_to (belongs_to
> :product_price)
> 2. If you nest the names in your form the form helpers aren''t
going to
> auto
> fill form values unless you use the form helper compound objects
> patch.
>
> So it''d probably be nicer not to nest the parameters and do:
>
> product.build_product_price( params[:product_price] )
> product.update_attributes( params[:product] )
>
Hi Nic,
thanks for reply
product.attributes produces the same error message
please see my other post for more explanation
Do you have something similiar working? I would be very grateful for any
hint how to make it work without workarounds
Here''s my schema...it''s simplified because in actual situation
it uses
inheritance on products, and product prices
create table products (
id int4 DEFAULT
nextval(''"products_id_seq"''::text) not null,
productNo varchar(250) not null,
description varchar(250) not null,
product_price_id int4 not null,
remark text,
brand_id int4,
model_id int4,
contact_id int4,
created_at timestamp not null,
updated_at timestamp not null,
primary key (id)
);
create table product_prices (
id int4 DEFAULT
nextval(''"product_prices_id_seq"''::text) not null,
costPrice numeric not null,
listPrice numeric not null,
primary key (id)
);
alter table products
add constraint fk_product_product_price
foreign key (price_id)
references product_prices;
Thank you very much
Peter
Nic Williams wrote:
>I assume that you have the correct database schema to match the attributes?
>
>Also, but I don''t know if there is any difference, try:
product.attributes >params[:product]
>
>If the latter fails, can you reply with your DB schema/sql statements?
>
>Cheers
>Nic
>
>
Peter Bohm wrote:> product.product_price.update_attributes(params[:product_price]) > product.update_attributes(params[:product])I didn''t know there was an update_attributes method for belongs_to associations. Does this code work?> I don''t use build_product_price because I am not able to use it with > single table inheritance - e.g. ProductPrice is a "base class" and it''s > extended by NetPrice, MarkupPrice, MarkdownPrice, etc. How do I pass the > actual implementation (class type) to the build_xxx method?You should be able to use build_net_price, build_markup_price, and build_markdown_price.> Anyways, why I brought the whole thing up is because it''s kind of > awkward to have another instance variable for nesting. There is a hint > of this in the agile book (table on p. 343) where the last row uses > user[address][city]=Wien for form parameters. That is translated to > {:user => {:address => {:city ="Wien"}}} and then used as > user.update_attributes(params[:user]). > However, I was neither able to get the form helpers to produce the > nested field nor use the update_attributes :-)Yes, p.343 does imply that update_attributes works for nested parameters. Though it''d probably work if address was an aggregration, it won''t work for associations. Perhaps you should submit an erratum at http://books.pragprog.com/titles/rails/errata . Nested parameters also don''t work with form helpers unless you use a patch I''ve placed on the dev site. Even then, the update_attributes and new methods won''t work unless you fiddle with the params to properly build the object chain. -- We develop, watch us RoR, in numbers too big to ignore.
Hi Mark, the code really works - I guess the first statement will create and save product_price object (which doesn''t have any database reference on Product) and the second will just create product and associate it with ProductPrice... build_net_price, etc. doesn''t work - I get NoMethodError Thank you very much for the rest of the explanation on the nested associations...I spent a few days on it not being able to work it out :-( But isn''t it something very common and natural to use associations in object oriented design? Peter Mark Reginald James wrote:> Peter Bohm wrote: > >> product.product_price.update_attributes(params[:product_price]) >> product.update_attributes(params[:product]) > > > I didn''t know there was an update_attributes method for belongs_to > associations. Does this code work? > >> I don''t use build_product_price because I am not able to use it with >> single table inheritance - e.g. ProductPrice is a "base class" and it''s >> extended by NetPrice, MarkupPrice, MarkdownPrice, etc. How do I pass the >> actual implementation (class type) to the build_xxx method? > > > You should be able to use build_net_price, build_markup_price, and > build_markdown_price. > >> Anyways, why I brought the whole thing up is because it''s kind of >> awkward to have another instance variable for nesting. There is a hint >> of this in the agile book (table on p. 343) where the last row uses >> user[address][city]=Wien for form parameters. That is translated to >> {:user => {:address => {:city ="Wien"}}} and then used as >> user.update_attributes(params[:user]). >> However, I was neither able to get the form helpers to produce the >> nested field nor use the update_attributes :-) > > > Yes, p.343 does imply that update_attributes works for nested > parameters. Though it''d probably work if address was an > aggregration, it won''t work for associations. Perhaps you should > submit an erratum at http://books.pragprog.com/titles/rails/errata . > > Nested parameters also don''t work with form helpers unless you > use a patch I''ve placed on the dev site. Even then, the > update_attributes and new methods won''t work unless you fiddle > with the params to properly build the object chain. >
Peter Bohm wrote:>>>product.product_price.update_attributes(params[:product_price]) >>>product.update_attributes(params[:product]) >> >>I didn''t know there was an update_attributes method for belongs_to >>associations. Does this code work?> the code really works - I guess the first statement will create and save > product_price object (which doesn''t have any database reference on > Product) and the second will just create product and associate it with > ProductPrice... Yes, I see now that product_price is just an AR object for which update_attributes works in its normal way. Associations just have some extra or overridden methods besides the normal ones. Useful to keep in mind. Peter Bohm wrote: > build_net_price, etc. doesn''t work - I get NoMethodError OK, I thought you had definitions "belongs_to :net_price", etc. -- We develop, watch us RoR, in numbers too big to ignore.
Hi Mark, Of course the point is to have a reference to ProductPrice and choose the implementation at runtime Thanks for the link to your patch as well Peter Mark Reginald James wrote:> Peter Bohm wrote: > >>>> product.product_price.update_attributes(params[:product_price]) >>>> product.update_attributes(params[:product]) >>> >>> >>> I didn''t know there was an update_attributes method for belongs_to >>> associations. Does this code work? >> > > > the code really works - I guess the first statement will create and > save > > product_price object (which doesn''t have any database reference on > > Product) and the second will just create product and associate it with > > ProductPrice... > > Yes, I see now that product_price is just an AR object for which > update_attributes works in its normal way. Associations just have > some extra or overridden methods besides the normal ones. Useful to > keep in mind. > > > Peter Bohm wrote: > > build_net_price, etc. doesn''t work - I get NoMethodError > > OK, I thought you had definitions "belongs_to :net_price", etc. >