2

作成して新しく作成した親に関連付ける必要があるレコードを表すネストされた配列を含む Rails 足場コントローラーに POST 要求を送信しようとしています。

JSON の例を次に示します。

{
    "plan_id":3,
    "weight":60,
    "exercise_sets": [
        {
            "created_at":"2012-06-13T14:55:57Z",
            "ended_at":"2012-06-13T14:55:57Z",
            "weight":"80.0",
            "repetitions":10,
            "exercise_id":1
        }
    ]
}

..そして私のモデル..

class Session < ActiveRecord::Base
  has_many :exercise_sets, :dependent => :destroy
  has_many :exercises, :through => :exercise_sets
end

class ExerciseSet < ActiveRecord::Base
  belongs_to :exercise
  belongs_to :session
end

私が試みていることは可能ですか?

4

2 に答える 2

5

This is certainly not impossible, though you may have to switch up your parameter naming a bit.

When you pass the JSON above to the controller, it either gets passed as parameters to a constructor:

Session.new(params[:session])

Or gets passed to the #update_attributes method on a persisted Session instance:

@session = Session.find(params[:id])
@session.update_attributes(params[:session])

Both the constructor and #update_attributes methods turn parameters like "plan_id" into assigment method calls. That is,

@session.update_attributes(:plan_id => "1")  

Turns into (inside the #update_attributes method):

@session.plan_id = "1"

So, this works for your plan_id and weight attributes, because you have both #plan_id= and #weight= setter methods. You also have an #exercise_sets= method given to you by has_many :exercise_sets. However, the #exercise_sets= method expects ExerciseSet objects, not ExerciseSet attributes.

Rails is capable of doing what you are trying to do via the #accepts_nested_attributes_for class method. Try this:

class Session < ActiveRecord::Base
  has_many :exercise_sets, :dependent => :destroy
  has_many :exercises, :through => :exercise_sets

  accepts_nested_attributes_for :exercise_sets
end

This sets up (metaprograms) an #exercise_sets_attributes= method for you. So just modify your JSON to:

{
    "plan_id":3,
    "weight":60,
    "exercise_sets_attributes": [
        {
            "created_at":"2012-06-13T14:55:57Z",
            "ended_at":"2012-06-13T14:55:57Z",
            "weight":"80.0",
            "repetitions":10,
            "exercise_id":1
        }
    ]
}

More info: http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

于 2012-06-25T19:59:13.683 に答える
0

It's perfectly possible, you just have to add the following line to your Session model:

  accepts_nested_attributes_for :exercise_sets, :reject_if => lambda { |a| a[:exercise_id].blank? }, :allow_destroy => true

Now, when your controller does Session.new(params[:session]), Rails will build (or update) the Session and the related ExerciceSet(s).

Please review the :reject_if clause. That's where you define which records will be created and which will not.

This are the basics, but Ryan Bates explains the nested model forms perfectly (as always) in this screencast.

于 2012-06-25T19:59:44.513 に答える