在 rails 中命名两个关联 has_many/belongs_to 失败
Naming both associations has_many/belongs_to in rails fails
我确信这是一个简单的问题,但我不明白为什么它不起作用。我有两个模型 RecipeInstruction
和 InstructionImage
。他们有 1:n 关系,我希望将他们的关联命名为 images
和 instruction
。我的模特:
class RecipeInstruction < ActiveRecord::Base
belongs_to :recipe
has_many :images, class_name: 'InstructionImage', autosave: true, inverse_of: :instruction
accepts_nested_attributes_for :images
end
class InstructionImage < ActiveRecord::Base
belongs_to :chef
belongs_to :instruction, class_name: 'RecipeInstruction', inverse_of: :images, foreign_key: :instruction_id
mount_uploader :file, PictureUploader
validates :chef_id, presence: true
validates :file, presence: true
validates :instruction_id, presence: true
end
但是下面的代码失败了:
instruction = RecipeInstruction.new({"id"=>"", "text"=>"", "position"=>"0", "images_attributes"=>{"0"=>{"file"=>'test.png'}}})
expect(instruction).to be_an_instance_of(RecipeInstruction)
和
Failure/Error: instruction = RecipeInstruction.new({"id"=>"", "text"=>"", "position"=>"0", "images_attributes"=>{"0"=>{"file"=>'test.png'}}})
NoMethodError:
undefined method `val' for "?":Arel::Nodes::BindParam
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/relation.rb:574:in `block (2 levels) in where_values_hash'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/relation.rb:570:in `fetch'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/relation.rb:570:in `block in where_values_hash'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/relation.rb:563:in `map'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/relation.rb:563:in `where_values_hash'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/relation.rb:581:in `scope_for_create'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/associations/collection_association.rb:483:in `create_scope'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/associations/association.rb:168:in `initialize_attributes'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/associations/association.rb:248:in `block in build_record'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/core.rb:274:in `initialize'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/inheritance.rb:61:in `new'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/inheritance.rb:61:in `new'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/reflection.rb:130:in `build_association'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/associations/association.rb:247:in `build_record'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/associations/collection_association.rb:130:in `build'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/nested_attributes.rb:465:in `block in assign_nested_attributes_for_collection_association'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/nested_attributes.rb:460:in `each'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/nested_attributes.rb:460:in `assign_nested_attributes_for_collection_association'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/nested_attributes.rb:343:in `images_attributes='
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/attribute_assignment.rb:54:in `public_send'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/attribute_assignment.rb:54:in `_assign_attribute'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/attribute_assignment.rb:65:in `block in assign_nested_parameter_attributes'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/attribute_assignment.rb:65:in `each'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/attribute_assignment.rb:65:in `assign_nested_parameter_attributes'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/attribute_assignment.rb:45:in `assign_attributes'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/core.rb:551:in `init_attributes'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/core.rb:272:in `initialize'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/inheritance.rb:61:in `new'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/inheritance.rb:61:in `new'
./spec/recipe_instruction_spec.rb:9:in `block (2 levels) in <top (required)>'
我找到了 foreign_key 列未定义的解决方案,但我找到了。我在 /Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/relation.rb
中调试了这个
def where_values_hash(relation_table_name = table_name)
equalities = where_values.grep(Arel::Nodes::Equality).find_all { |node|
node.left.relation.name == relation_table_name
}
binds = Hash[bind_values.find_all(&:first).map { |column, v| [column.name, v] }]
Hash[equalities.map { |where|
name = where.left.name
puts 'debug'
puts @klass.inspect
puts @table.inspect
puts name.inspect
puts where.inspect
[name, binds.fetch(name.to_s) {
case where.right
when Array then where.right.map(&:val)
else
where.right.val
end
}]
}]
end
这里是调试:
InstructionImage(id: integer, file: string, chef_id: integer, instruction_id: integer, created_at: datetime, updated_at: datetime)
#<Arel::Table:0x007f9ec4a9d688 @name="instruction_images", @engine=InstructionImage(id: integer, file: string, chef_id: integer, instruction_id: integer, created_at: datetime, updated_at: datetime), @columns=nil, @aliases=[], @table_alias=nil, @primary_key=nil>
"recipe_instruction_id"
#<Arel::Nodes::Equality:0x007f9ec4a155a8 @left=#<struct Arel::Attributes::Attribute relation=#<Arel::Table:0x007f9ec4a15f30 @name="instruction_images", @engine=ActiveRecord::Base, @columns=nil, @aliases=[], @table_alias=nil, @primary_key=nil>, name="recipe_instruction_id">, @right="?">
为什么名字是recipe_instruction_id
。关系名称是 instruction
,我将它的外键定义为 instruction_id
。这是错误吗?我该如何解决?
谢谢
您应该在 RecipeInstruction class 中定义 foreign_id。
class RecipeInstruction < ActiveRecord::Base
belongs_to :recipe
has_many :images, class_name: 'InstructionImage', autosave: true, foreign_key: "instruction_id"
accepts_nested_attributes_for :images
end
我确信这是一个简单的问题,但我不明白为什么它不起作用。我有两个模型 RecipeInstruction
和 InstructionImage
。他们有 1:n 关系,我希望将他们的关联命名为 images
和 instruction
。我的模特:
class RecipeInstruction < ActiveRecord::Base
belongs_to :recipe
has_many :images, class_name: 'InstructionImage', autosave: true, inverse_of: :instruction
accepts_nested_attributes_for :images
end
class InstructionImage < ActiveRecord::Base
belongs_to :chef
belongs_to :instruction, class_name: 'RecipeInstruction', inverse_of: :images, foreign_key: :instruction_id
mount_uploader :file, PictureUploader
validates :chef_id, presence: true
validates :file, presence: true
validates :instruction_id, presence: true
end
但是下面的代码失败了:
instruction = RecipeInstruction.new({"id"=>"", "text"=>"", "position"=>"0", "images_attributes"=>{"0"=>{"file"=>'test.png'}}})
expect(instruction).to be_an_instance_of(RecipeInstruction)
和
Failure/Error: instruction = RecipeInstruction.new({"id"=>"", "text"=>"", "position"=>"0", "images_attributes"=>{"0"=>{"file"=>'test.png'}}})
NoMethodError:
undefined method `val' for "?":Arel::Nodes::BindParam
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/relation.rb:574:in `block (2 levels) in where_values_hash'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/relation.rb:570:in `fetch'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/relation.rb:570:in `block in where_values_hash'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/relation.rb:563:in `map'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/relation.rb:563:in `where_values_hash'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/relation.rb:581:in `scope_for_create'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/associations/collection_association.rb:483:in `create_scope'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/associations/association.rb:168:in `initialize_attributes'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/associations/association.rb:248:in `block in build_record'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/core.rb:274:in `initialize'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/inheritance.rb:61:in `new'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/inheritance.rb:61:in `new'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/reflection.rb:130:in `build_association'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/associations/association.rb:247:in `build_record'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/associations/collection_association.rb:130:in `build'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/nested_attributes.rb:465:in `block in assign_nested_attributes_for_collection_association'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/nested_attributes.rb:460:in `each'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/nested_attributes.rb:460:in `assign_nested_attributes_for_collection_association'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/nested_attributes.rb:343:in `images_attributes='
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/attribute_assignment.rb:54:in `public_send'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/attribute_assignment.rb:54:in `_assign_attribute'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/attribute_assignment.rb:65:in `block in assign_nested_parameter_attributes'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/attribute_assignment.rb:65:in `each'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/attribute_assignment.rb:65:in `assign_nested_parameter_attributes'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/attribute_assignment.rb:45:in `assign_attributes'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/core.rb:551:in `init_attributes'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/core.rb:272:in `initialize'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/inheritance.rb:61:in `new'
/Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/inheritance.rb:61:in `new'
./spec/recipe_instruction_spec.rb:9:in `block (2 levels) in <top (required)>'
我找到了 foreign_key 列未定义的解决方案,但我找到了。我在 /Users/alias/.rvm/src/rvm/gems/ruby-2.1.6/gems/activerecord-4.2.0.beta2/lib/active_record/relation.rb
def where_values_hash(relation_table_name = table_name)
equalities = where_values.grep(Arel::Nodes::Equality).find_all { |node|
node.left.relation.name == relation_table_name
}
binds = Hash[bind_values.find_all(&:first).map { |column, v| [column.name, v] }]
Hash[equalities.map { |where|
name = where.left.name
puts 'debug'
puts @klass.inspect
puts @table.inspect
puts name.inspect
puts where.inspect
[name, binds.fetch(name.to_s) {
case where.right
when Array then where.right.map(&:val)
else
where.right.val
end
}]
}]
end
这里是调试:
InstructionImage(id: integer, file: string, chef_id: integer, instruction_id: integer, created_at: datetime, updated_at: datetime)
#<Arel::Table:0x007f9ec4a9d688 @name="instruction_images", @engine=InstructionImage(id: integer, file: string, chef_id: integer, instruction_id: integer, created_at: datetime, updated_at: datetime), @columns=nil, @aliases=[], @table_alias=nil, @primary_key=nil>
"recipe_instruction_id"
#<Arel::Nodes::Equality:0x007f9ec4a155a8 @left=#<struct Arel::Attributes::Attribute relation=#<Arel::Table:0x007f9ec4a15f30 @name="instruction_images", @engine=ActiveRecord::Base, @columns=nil, @aliases=[], @table_alias=nil, @primary_key=nil>, name="recipe_instruction_id">, @right="?">
为什么名字是recipe_instruction_id
。关系名称是 instruction
,我将它的外键定义为 instruction_id
。这是错误吗?我该如何解决?
谢谢
您应该在 RecipeInstruction class 中定义 foreign_id。
class RecipeInstruction < ActiveRecord::Base
belongs_to :recipe
has_many :images, class_name: 'InstructionImage', autosave: true, foreign_key: "instruction_id"
accepts_nested_attributes_for :images
end