I'm using the Solidus eCommerce gem for Ruby on Rails. I'm creating an eCommerce website for sending mail, so I need to be able to attach addresses to individual line items, rather than just the user's billing and shipping addresses. In order to accomplish that, I'm passing address parameters in the cart form.
I'm getting Unpermitted parameter: address_attributes
. Here are the parameters I'm passing in through my form:
parameters
Parameters: {"utf8"=>"✓", "authenticity_token"=>"[AUTHENTICITY_TOKEN]", "content"=>"",
"order"=>{"address_attributes"=>[{"firstname"=>"", "lastname"=>"", "address1"=>"", "address2"=>"", "city"=>"", "country_id"=>"232", "state_id"=>"", "zipcode"=>"", "phone"=>""}]}, "variant_id"=>"1", "quantity"=>"1", "button"=>""}
Here's how I'm accessing them: address_attributes = order_params[:address_attributes]
.
Here's the order_params method that comes with Solidus:
orders_controller.rb
def order_params
if params[:order]
params[:order].permit(*permitted_order_attributes)
else
{}
end
end
(I'm not sure why it uses this if else logic instead of params.require, but it's not my code.) When I put a debugger in there, and look at permitted_order_attributes
this is what I see:
[:coupon_code, :email, :special_instructions, :use_billing, {:bill_address_attributes=>[:id, :firstname, :lastname, :first_name, :last_name, :address1, :address2, :city, :country_id, :state_id, :zipcode, :phone, :state_name, :country_iso, :alternative_phone, :company, {:country=>[:iso, :name, :iso3, :iso_name], :state=>[:name, :abbr]}], :ship_address_attributes=>[:id, :firstname, :lastname, :first_name, :last_name, :address1, :address2, :city, :country_id, :state_id, :zipcode, :phone, :state_name, :country_iso, :alternative_phone, :company, {:country=>[:iso, :name, :iso3, :iso_name], :state=>[:name, :abbr]}], :payments_attributes=>[:amount, :payment_method_id, :payment_method, {:source_attributes=>[:number, :month, :year, :expiry, :verification_value, :first_name, :last_name, :cc_type, :gateway_customer_profile_id, :gateway_payment_profile_id, :last_digits, :name, :encrypted_data, :existing_card_id,
{
:address_attributes=>[
:id, :firstname, :lastname, :first_name, :last_name, :address1, :address2, :city, :country_id, :state_id, :zipcode, :phone, :state_name, :country_iso, :alternative_phone, :company, {:country=>[:iso, :name, :iso3, :iso_name], :state=>[:name, :abbr]}
]
}
]}], :shipments_attributes=>[:special_instructions, :stock_location_id, :id, :tracking, :selected_shipping_rate_id]}, {:line_items_attributes=>[:id, :variant_id, :quantity]}]
So, there are the address_attributes. What's odd is that they're wrapped in {}
. My understanding is that that means it's looking for parameters that look like this: "order"=>{["address_attributes"=>{"firstname"=>"
...etc. But I'm not positive. I'm not sure why Solidus is looking for the parameters to be passed in that way, and I'm not sure how to write my form so that it passes paramaters like that. Here's my form:
_cart_form.html.erb
<%= f.fields_for('address_attributes[][]', @address) do |form| %>
<%= render :partial => 'spree/address/form', :locals => { form: form,
address_type: 'shipping', address: @address } %>
<% end %>
work around
If I change the order params method to this:
def order_params
params.require(:order).permit(:address_attributes=>[:id, :firstname, :lastname, :first_name, :last_name, :address1, :address2, :city, :country_id, :state_id, :zipcode, :phone, :state_name, :country_iso, :alternative_phone, :company, {:country=>[:iso, :name, :iso3, :iso_name], :state=>[:name, :abbr]}])
end
then my form works. So, I have a work around, but I'd like to understand what's going on here. There are a few ways to solve this problem:
order_params
expectations.I dumped what you are getting for permitted_order_attributes
into a JSON formatting tool that I like to use, and go this:
[
: coupon_code,
: email,
: special_instructions,
: use_billing,
{
: bill_address_attributes=>[
: id,
: firstname,
: lastname,
: first_name,
: last_name,
: address1,
: address2,
: city,
: country_id,
: state_id,
: zipcode,
: phone,
: state_name,
: country_iso,
: alternative_phone,
: company,
{
: country=>[
: iso,
: name,
: iso3,
: iso_name
],
: state=>[
: name,
: abbr
]
}
],
: ship_address_attributes=>[
: id,
: firstname,
: lastname,
: first_name,
: last_name,
: address1,
: address2,
: city,
: country_id,
: state_id,
: zipcode,
: phone,
: state_name,
: country_iso,
: alternative_phone,
: company,
{
: country=>[
: iso,
: name,
: iso3,
: iso_name
],
: state=>[
: name,
: abbr
]
}
],
: payments_attributes=>[
: amount,
: payment_method_id,
: payment_method,
{
: source_attributes=>[
: number,
: month,
: year,
: expiry,
: verification_value,
: first_name,
: last_name,
: cc_type,
: gateway_customer_profile_id,
: gateway_payment_profile_id,
: last_digits,
: name,
: encrypted_data,
: existing_card_id,
{
: address_attributes=>[
: id,
: firstname,
: lastname,
: first_name,
: last_name,
: address1,
: address2,
: city,
: country_id,
: state_id,
: zipcode,
: phone,
: state_name,
: country_iso,
: alternative_phone,
: company,
{
: country=>[
: iso,
: name,
: iso3,
: iso_name
],
: state=>[
: name,
: abbr
]
}
]
}
]
}
],
: shipments_attributes=>[
: special_instructions,
: stock_location_id,
: id,
: tracking,
: selected_shipping_rate_id
]
},
{
: line_items_attributes=>[
: id,
: variant_id,
: quantity
]
}
]
It looks to me as if the only occurrence of address_attributes
is nested inside payment_attributes
> source_attributes
. This sounds like your desired structure is broken somehow.
You may be better to ignore their suggested code for your protected params, and to explicitly structure what you want in the normal way:
def order_params
params.require(:order).permit(:your, :choice, :of, :fields,
address_attributes: [:address, :fields],
other_nested_thing_attributes: [:stuff, :here])
end
You'd be 100% in control of what you want to accept from your forms. This would also help you to highlight errors in your form structure.
HTH - comments or questions, just shout.