问题
I have a form which creates a new Child record and a new Parent record using accepts_nested_attributes_for
Children and Parents have a has_many :through
association like so:
class Child < ActiveRecord::Base
has_many :relationships
has_many :parents, through: :relationships
accepts_nested_attributes_for :parents
accepts_nested_attributes_for :relationships, allow_destroy: true
end
class Parent < ActiveRecord::Base
has_many :relationships
has_many :children, through: :relationships
end
class Relationship < ActiveRecord::Base
belongs_to :child
belongs_to :parent
accepts_nested_attributes_for :parents
#has :schedule attribute
end
I would like to set the schedule
attribute in Relationships at the same time and can't use accepts_nested_attributes_for
as I am manipulating some data in the controller to determine the schedule
object before saving.
There are many answers on stack overflow for accomplishing this with a pre-existing parent record but I am having trouble finding any for a situation where none of the associations exist previously.
I have tried to do this with an after_create
callback in the model but don't have access to params
and have read that it is bad procedure to do so anyway. ( Rails How to pass params from controller to after_save inside model).
Ideally I would like to set schedule
in the same database call that creates the relationship record along with child_id
and parent_id
.
Any help with this would be awesome, thanks
UPDATE
Controller as of original post
def new
@child = Child.new
end
def create
@child = Child.new(params[:child])
schedule = build_schedule(params)
# Need to save schedule to @child.relationship[0].schedule somehow
if @child.save!
redirect_to admins_path
else
render 'new'
end
end
private
def build_schedule(params)
# works with params[:mon, :tue, :wed, :thu, :fri] to return a schedule object.
end
The parent
is built using Ryan Bates' nested form helper. This is the build line from it:
module ApplicationHelper
def link_to_add_fields(name, f, association)
new_object = f.object.send(association).klass.new
...
end
end
I am not building the relationship
at all, it is magically built by rails as far as i'm aware.
Trying Danny Van Hoof's suggestion @child.relationships[0].schedule =
i get undefined method schedule=' for nil:NilClass
as no relationship exists.
If i build the relationship beforehand either in new
or create
action using @child.relationship.build
I get 2 relationship records being saved:

The one that I built has schedule
saved but has no parent_id
(parental_group_id)
The second record is the one build magically and has both correct ids but no schedule
.
Now when trying Rick Peck's suggestion by adding
def params
params.require(:child).permit(relationships_attributes: [:schedule])
# tried with and without `parents_attributes`
end
I get a stack level too deep
error on the params.require
line. I also don't fully understand what this does. (I'm fairly new to rails)
Thanks for helping!
回答1:
I have a similar construct as yours in one of my websites, it works fine, except that I (translated to your example) have
attr_accessible :relationships_attributes
accepts_nested_attributes_for :relationships, allow_destroy: true
In my Relationship model, I then make parent_id accessible
This allows to, in the controller, to do something like
@child.relationships[0].schedule = ...
Even before saving the child
Or, alternatively, to set the schedule from your view immediately when entering the parent details
Just drop me a comment if not clear!
回答2:
Firstly, your accepts_nested_attributes_for
will have to include the join model
, and then pass the data through to the other model, like this:
class Child < ActiveRecord::Base
has_many :relationships
has_many :parents, through: :relationships
accepts_nested_attributes_for :relationships
end
class Parent < ActiveRecord::Base
has_many :relationships
has_many :children, through: :relationships
end
class Relationship < ActiveRecord::Base
belongs_to :child
belongs_to :parent
#attr_accessor :schedule ?
accepts_nested_attributes_for :parents
end
#app/controllers/child_controller.rb
def new
@child = Child.new
@child.relationships.build.parents.build
end
private
def params
params.require(:child).permit(relationships_attributes: [:schedule, parents_attributes: [:variable-1, :variable-2]])
end
This will pass the required data to relationships
and then onto parents
. The schedule
can be then handled when you handle the variables in the relationships
model
来源:https://stackoverflow.com/questions/20295658/how-to-save-attributes-to-a-has-many-through-join-table-with-no-existing-record