4

I'm new on a project and trying to add a feature to a system that already has a bunch of moving parts, most of which I don't believe are at all related to the functionality I'm trying to add.

I want to add fields to an ActiveAdmin/Formtastic form to allow users to create and update pricing schemes associated with products. Each product has one pricing scheme which can have many pricing tiers.

The fields show up on the form, but when I update the product object, the fee and max attributes in the pricing tier object aren't saved to the database

The ActiveAdmin form has a variable, pricing_scheme_object, which I created based off of this Stack Overflow Answer. The ActiveAdmin form looks like:

ActiveAdmin.register Product do
  actions :all, except: [:destroy]
  # menu parent, filters, and scopes, none of which are related
  form html: {multipart: true} do |f|
    f.inputs "Product" do
      # unrelated code
      pricing_scheme_object = [:pricing_scheme, f.object.pricing_scheme ||
                               PricingScheme.new]
      f.inputs "Pricing Schemes", :for => pricing_scheme_object do |scheme|
        scheme.has_many :pricing_tiers do |tier|
          tier.input :fee, input_html: { class: 'pricing_scheme_column'}, size: 5
          tier.input :max, input_html: { class: 'pricing_scheme_column'}, size: 5
        end
      end
      # unrelated code
    end
    f.actions
  end
  # unrelated code
end

When I save a product I see the following on the server:

Started PUT "/admin/products/139" for 127.0.0.1 at 2013-03-20 12:50:43 -0700
Processing by Admin::ProductsController#update as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"FzyjTkrTF0LvB1K02kebSgqDQWad8c5/bpbIEhFgQpY=", "product"=>{"three_letter_acronym_id"=>"64", "name"=>"test pdf", "description"=>"<p>this is the pdf </p><div class=\"vimiumReset vimiumHUD\" style=\"right: 150px; opacity: 0; display: none; \"></div>", "status"=>"published", "way"=>"pdf", "custom_path"=>"", "pricing_scheme"=>{"pricing_tiers_attributes"=>{"1363809038085"=>{"fee"=>"30", "max"=>"10"}}}, "allocation_rule_number"=>"", "fulfillment_email"=>"", "fulfillment_username"=>"", "fulfillment_password"=>"[FILTERED]", "fulfillment_url"=>"",  "shared_secret"=>"", "api_key"=>"", "callback_url"=>""}, "commit"=>"Update Product", "id"=>"139"}
  Product Load (0.4ms)  SELECT `products`.* FROM `products` WHERE `products`.`id` = 139 LIMIT 1
WARNING: Can't mass-assign protected attributes: pricing_scheme
   (0.1ms)  BEGIN
[paperclip] Saving attachments.
   (0.1ms)  COMMIT
Redirected to http://localhost:3000/admin/products/139
Completed 302 Found in 119ms (ActiveRecord: 0.0ms)


Started GET "/admin/products/139" for 127.0.0.1 at 2013-03-20 12:50:43 -0700
Processing by Admin::ProductsController#show as HTML
  Parameters: {"id"=>"139"}
  Product Load (0.3ms)  SELECT `products`.* FROM `products` WHERE `products`.`id` = 139 LIMIT 1
  ThreeLetterAcronym Load (0.4ms)  SELECT `three_letter_acronym`.* FROM `three_letter_acronym` WHERE `three_letter_acronym`.`id` = 64 LIMIT 1
  Rendered /Users/strand/.rvm/gems/ruby-1.9.3-p392/bundler/gems/active_admin-c3be25319bb6/app/views/active_admin/resource/show.html.arb (27.3ms)
Completed 200 OK in 144ms (Views: 29.0ms | ActiveRecord: 0.6ms)

The product looks like this:

# app/models/product.rb
class Product < ActiveRecord::Base
  # … (probably unrelated code)
  has_one  :pricing_scheme, dependent: :destroy
  accepts_nested_attributes_for :pricing_scheme, allow_destroy: true, reject_if: lambda { |a| a[:price].blank? }
  # … 
  attr_accessible :unrelated_attributes,
                  :pricing_scheme_attributes,
                  :pricing_scheme_id
  # …
end

The pricing scheme model is:

# app/models/pricing_scheme.rb
class PricingScheme < ActiveRecord::Base

  attr_accessible :display_order, :label, :product_id, :max_quantity,
                  :min_quantity, :price, :category, :pricing_tiers_attributes

  has_many   :pricing_tiers
  belongs_to :product

  accepts_nested_attributes_for :pricing_tiers, :allow_destroy => true

  def price_for(number)
    # logic to determine the price for a number of products based on the pricing 
    # tiers associated with the pricing scheme.
  end
end

The pricing tier looks like:

# app/models/pricing_tier.rb
class PricingTier < ActiveRecord::Base
  attr_accessible :fee, :max, :base, :pricing_scheme_id

  belongs_to :pricing_scheme
end

When I save the product, I would like to update or create the pricing scheme and any pricing tiers which are associated with it.

How do I do this?

Community
  • 1
  • 1
Strand McCutchen
  • 3,157
  • 1
  • 16
  • 8
  • Your `Product` model has an `attr_accessible :pricing_scheme_id`. It should not, since it's a `has_one`. In a `has_one`:`belongs_to` relationship, the `belongs_to` model should have the foreign key id. Probably won't solve the issue, but probably worth getting rid of that on `Product`. – Josh Kovach Mar 26 '13 at 01:41

2 Answers2

0

Try adding :pricing_scheme as the first object in the pricing_scheme_object array, i.e.

f.inputs "Pricing Schemes", :for => [:pricing_scheme, f.object.pricing_scheme || PricingScheme.new] do |scheme|
  scheme.has_many :pricing_tiers do |tier|
    tier.input :fee, input_html: { class: 'pricing_scheme_column'}, size: 5
    tier.input :max, input_html: { class: 'pricing_scheme_column'}, size: 5
  end
end

The problem seems that it's passing in params[:pricing_scheme] rather than params[:pricing_scheme_attributes], and according to the answer from which you built your inputs, the field name should be passed in the :for options to tell it what attributes they should be for.

Josh Kovach
  • 7,679
  • 3
  • 45
  • 62
  • Can you post what your server output is since updating with this patch? If it's still passing `"pricing_scheme" => {...}` instead of `"pricing_scheme_attributes" => {...}` then I think it must still be related to how you're creating the nested form for the scheme. – Josh Kovach Mar 26 '13 at 01:59
0

You're PUT ing to License, so you may need the accepts_nested_attributes_for :pricing_tiers in License?

Ivan -Oats- Storck
  • 4,096
  • 3
  • 30
  • 39
  • Hmmm, I don't think so. The relationship looks like this: Product -one-> Pricing Scheme -many-> Pricing Tier I tried adding accepts_nested_attributes_for :pricing_tiers and got an error unless I also had a has_many relationship in Product. – Strand McCutchen Mar 21 '13 at 19:53