我正在开发一个产品模型,该模型与自身具有has_one关联,包括原材料记录。模型通过REST API返回数据。我使用的是Active Model Serializer而不是JBuilder。
产品型号有一个'代码'包含字符串中的产品代码的字段:
StatusCode
只有两个代码之间的差异是右起第三个数字。 ' 1'是产品。 ' 0'是物质的。我想要包含一个" raw_material"检索产品记录时记录。所以,我尝试将has_one关联设置为具有"其中"子句(稍后我可以撰写查询以从产品代码中获取材料)。现在我只是通过" product" lambda中的对象并在其中使用它。
首先我在def raw_material中写道,这是有效的。但是,我不知道如何将对象传递给def并在where子句中使用它。因此,我在has_one中提出了范围模式,但即使它生成与def模式完全相同的SELECT,它也会返回错误。我得到了#No; NoMethodError"代替。
'001-000-01-01' (This is a product.)
'001-000-00-01' (This is a material.)
" def"模式有效:
class Product < ActiveRecord::Base
has_many :supplies, ->{order('row_order ASC') }, primary_key: :code, foreign_key: :product_code
#This Works!
#has_one :raw_material, class_name: 'Product', primary_key: :code, foreign_key: :code
#This Works!
#has_one :raw_material
#Does not work. Why?
has_one :raw_material, ->(product) { where('code = ?', product.code).take }, class_name: 'Product'
accepts_nested_attributes_for :supplies, allow_destroy: true
#def raw_material
# Product.where('code = ?', '001-000-01-01').take
#end
end
但是,范围模式不起作用:
Started GET "/products/1.json" for ::1 at 2016-10-05 21:48:15 +0900
Processing by ProductsController#show as JSON
Parameters: {"id"=>"1"}
Product Load (0.3ms) SELECT "products".* FROM "products" WHERE "products"."id" = ? LIMIT 1 [["id", 1]]
[active_model_serializers] Supply Load (0.1ms) SELECT "supplies".* FROM "supplies" WHERE "supplies"."product_code" = ? ORDER BY row_order ASC [["product_code", "031-052-00-01"]]
[active_model_serializers] Product Load (0.1ms) SELECT "products".* FROM "products" WHERE (code = '001-000-01-01') LIMIT 1
[active_model_serializers] Rendered ProductSerializer with ActiveModelSerializers::Adapter::Attributes (6.71ms)
Completed 200 OK in 24ms (Views: 9.2ms | ActiveRecord: 1.4ms)
Product Controller只是定义了这样的节目:
Started GET "/products/1.json" for ::1 at 2016-10-06 08:19:13 +0900
Processing by ProductsController#show as JSON
Parameters: {"id"=>"1"}
Product Load (0.1ms) SELECT "products".* FROM "products" WHERE "products"."id" = ? LIMIT 1 [["id", 1]]
[active_model_serializers] Supply Load (0.1ms) SELECT "supplies".* FROM "supplies" WHERE "supplies"."product_code" = ? ORDER BY row_order ASC [["product_code", "031-052-00-01"]]
[active_model_serializers] Product Load (0.1ms) SELECT "products".* FROM "products" WHERE (code = '031-052-00-01') LIMIT 1
[active_model_serializers] Rendered ProductSerializer with ActiveModelSerializers::Adapter::Attributes (10.6ms)
Completed 500 Internal Server Error in 27ms (ActiveRecord: 1.2ms)
NoMethodError (undefined method `except' for #<Product:0x007fe97b090418>):
app/controllers/products_controller.rb:17:in `block (2 levels) in show'
app/controllers/products_controller.rb:14:in `show'
Rendered vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.5/lib/action_dispatch/middleware/templates/rescues/_source.erb (8.8ms)
product_serializer.rb是:
# GET /products/1
# GET /products/1.json
def show
respond_to do |format|
format.html
format.json do
render json: @product, include: ['raw_material']
end
end
end
非常感谢任何帮助。
谢谢
更新
我自己解决了这个问题。请检查下面的答案。感谢所有撰写解决方案的人。
答案 0 :(得分:0)
# Does not work. Why?
has_one :raw_material ->(product) { where('code = ?', product.code).take }...
因为你试图在这里定义一个范围......而不是一个关联。如果你想要一个范围,请使用范围,例如:
scope :raw_material ->(product) { where('code = ?', product.code).first }
如果您想要关联,请使用关联,例如
has_one :raw_material, class_name: 'Product', primary_key: :code, foreign_key: :code
不要试图将两者混合在一起。
答案 1 :(得分:0)
您可以按如下方式自定义has_one:raw_material。
class ProductSerializer < ActiveModel::Serializer
attributes(*Product.attribute_names.map(&:to_sym))
has_one :raw_material do
Product.where(code: object.code)
end
end
答案 2 :(得分:0)
我自己可以解决这个问题。因为我不必在一行中写这个,所以def(方法)模式是最好的选择。如何覆盖“has_many”可以帮助我解决问题。
Overriding a has_many association getter
“self”可用于has_one以获取def中的对象。
has_one :raw_material
def raw_material
Product.where('code like ?', (self.code)[0,9] + '_' + (self.code)[10,3]).take
end
这样可以在模型中生成您喜欢的任何数据集。