[英]NoMethodError: undefined method '' for nil:NilClass
I have these models and controller codes: 我有以下模型和控制器代码:
class Item < ActiveRecord::Base
has_many :receivers_collateral_items, through: :received_trades, source: :wanted_item
has_many :receivers_wanted_items, through: :received_trades, source: :collateral_item
has_many :requesters_collateral_items, through: :requested_trades, source: :collateral_item
has_many :requesters_wanted_items, through: :requested_trades, source: :wanted_item
validates :year, :price, presence: true, numericality: true
validates :shares, numericality:
{ only_integer: true, greater_than_or_equal_to: 0,
less_than_or_equal_to: :build_shares }
accepts_nested_attributes_for :receivers_collateral_items, :receivers_wanted_items,
:requesters_collateral_items, :requesters_wanted_items,
allow_destroy: true
end
class Trade < ActiveRecord::Base
belongs_to :trade_requester, class_name: "User"
belongs_to :trade_recipient, class_name: "User"
belongs_to :wanted_item, class_name: "Item"
belongs_to :collateral_item, class_name: "Item"
validates :trade_requester, :trade_recipient, :wanted_item, :collateral_item, presence: true
validates :shares, numericality:
{ only_integer: true, greater_than_or_equal_to: 0,
less_than_or_equal_to: :max_shares }
accepts_nested_attributes_for :wanted_item, :collateral_item, allow_destroy: true
def max_shares
if wanted_item.shares > collateral_item.shares
collateral_item.shares
else
wanted_item.shares
end
end
end
class TradesController < ApplicationController
def create
@trade = current_user.requested_trades.build(trade_params)
end
private
def trade_params
params.require(:trade).permit(:trade_requester_id, :trade_recipient_id, :wanted_item_id, :collateral_item_id, :shares)
end
end
But I'm getting NoMethodError: undefined method 'shares' for nil:NilClass
and a bd rollback. 但是我得到了
NoMethodError: undefined method 'shares' for nil:NilClass
和bd回滚的NoMethodError: undefined method 'shares' for nil:NilClass
。 Steps to reproduce error: 重现错误的步骤:
t = Trade.new
t.trade_requester_id = User.find(1)
t.trade_recipient_id = User.find(2)
t.wanted_item_id = Item.second
t.collateral_item_id = Item.first
t.shares = 100
t.save
The stack trace indicates that it comes from the numericality
validation in Trade
, but it seems to me that the class shares
is being called on should exist. 堆栈跟踪表明它来自
Trade
的numericality
验证,但在我看来, 应该存在被调用的类shares
。 I should be able to call t.wanted_item
and get that item, but instead I get nil
. 我应该能够调用
t.wanted_item
并获得该项目,但我得到nil
。 t.wanted_item_id
, however, returns that id. t.wanted_item_id
,但是,返回该ID。 Why is this? 为什么是这样?
This is probably because the new record does is missing a wanted_item
or a collateral_item
. 这可能是因为新记录确实缺少了
wanted_item
或collateral_item
。 If either of this two associations returns nil
, then an exception will be thrown. 如果这两个关联中的
nil
一个返回nil
,则将引发异常。 To fix this use try
for older versions of Ruby, or the safe navigation operator ( &.
) for Ruby 2.3 or later. 要解决此问题,请
try
使用较旧版本的Ruby,或使用安全导航操作符( &.
)进行Ruby 2.3或更高版本。
This should solve your issue (pre Ruby 2.3): 这应该可以解决您的问题(Ruby 2.3之前的版本):
def max_shares
if wanted_item.try(:shares).to_i > collateral_item.try(:shares).to_i
wanted_item.shares
else
collateral_item.try(:shares).to_i
end
end
The try
method will return the value of wanted_item.shares
and collateral_item.shares
if they are not nil
. 如果
wanted_item.shares
和collateral_item.shares
不是nil
则try
方法将返回它们的值。 If one of them is nil
then try
will catch the exception and return nil
. 如果其中之一为
nil
则try
将捕获异常并返回nil
。 The to_i
converts nil
to zero. to_i
将nil
转换为零。
So collateral_item.try(:shares).to_i
will return the value of shares
if collateral_item
exists, and it will return zero if collateral_item
is nil
. 因此,如果存在
collateral_item
, collateral_item.try(:shares).to_i
将返回shares
的价值,如果collateral_item
为nil
,它将返回零。
If you are using Ruby 2.3 or later, you should to replace _item.try(:shares).to_i
with _item&.shares.to_i
. 如果使用Ruby 2.3或更高版本,则应将
_item.try(:shares).to_i
为_item&.shares.to_i
。 The latter is cleaner looking and faster in execution . 后者看起来更干净,执行速度更快 。
Update 更新资料
For replication, be sure you are assigning records to your associations and not to their ids: 为了进行复制,请确保将记录分配给关联而不是其ID:
t = Trade.new
t.trade_requester = User.find(1)
t.trade_recipient = User.find(2)
t.wanted_item = Item.second
t.collateral_item = Item.first
t.shares = 100
t.save!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.