【问题标题】:Calling methods in other models in controller在控制器中调用其他模型中的方法
【发布时间】:2016-07-14 13:10:01
【问题描述】:

因此,我对将影响数据库的功能卸载到模型而不是控制器的概念非常陌生,并且在使其工作时遇到了一些困难。

基本上,从我的Stock 控制器,我试图在我的User 模型中调用一个方法。相反,我收到了一个错误:

NoMethodError (undefined method `stock_relationships' for #<Class:0x007fc0da1a8d60>):
  app/models/user.rb:27:in `follow_stock'
  app/controllers/stocks_controller.rb:20:in `add_stock'

所以,这就是我所拥有的:

用户在 views/stocks/index.html.erb 中添加股票

<% @stocks.each do |s| %>
  <tr>
    <td><%= s.symbol %></td>
    <td><%= s.name %></td>
    <td>
       <%= link_to raw("<i class='fa fa-plus'></i>"), add_stock_path(id: s.id) %>
    </td>
  </tr>
<% end %>

然后触发 StockController add_stock 方法:

def add_stock
    stock = Stock.find(params[:id])
    user = current_user.id
    User.follow_stock(stock_id: stock, user_id: user)
    flash[:success] = "Successfully added stock"
    redirect :back
end

方法中的第 3 行是我的问题所在,因为 follow_stock 方法位于 User 模型中:

class User < ActiveRecord::Base

  has_many :stock_relationships
  has_many :stocks, through: :stock_relationships

  def self.follow_stock(stock)
    self.stock_relationships.create(stock_id: stock)
  end
end

有人可以帮我弄清楚如何实际调用此方法,还是我完全不了解我的尝试方式?

更新

我已经更改了一些代码,现在我可以创建 StockRelationship 但是,stock_id 正在保存为 nil

=> #<StockRelationship:0x007fee03f25f00
 id: 17,
 user_id: 1,
 stock_id: nil,
 created_at: Thu, 14 Jul 2016 13:44:52 UTC +00:00,
 updated_at: Thu, 14 Jul 2016 13:44:52 UTC +00:00>

我更改了StockController#add_stock中的代码:

def add_stock
    stock = Stock.find(params[:id])
    current_user.follow_stock(stock)
    flash[:success] = "Successfully added stock"
    redirect_to :back
end

【问题讨论】:

  • #stock_relationships 是一个实例方法,您在User 类上调用它,而不是在User 实例上调用它,这就是问题所在。将def self.follow_stock(stock) 更改为def follow_stock(stock)。并像user.follow_stock(stock)一样打电话

标签: ruby-on-rails ruby activerecord


【解决方案1】:

你可以通过重构逐渐让你的代码简洁。

首先,让我们在控制器中编写实现:

def add_stock
  stock = Stock.find(params[:id])
  current_user.stock_relationships.create(stock: stock)
  flash[:success] = "Successfully added stock"
  redirect :back
end

这不是太多的代码,而且足够简洁。在我看来,我认为代码不需要重构,但如果你坚持将逻辑放到User模型中以增强表现力,比如

def add_stock
  stock = Stock.find(params[:id])
  current_user.follow_stock(stock)
  flash[:success] = "Successfully added stock"
  redirect :back
end

那么我们需要实现User#follow_stock。注意我在符号中使用了#,这意味着follow_stock应该是一个实例方法,而不是一个类方法。

class User < ActiveRecord::Base
  def follow_stock(stock)
    stock_relationships.create(user: self)
  end
end

我只是做了一些复制和粘贴(邪恶?不在重构阶段。),并将current_user 替换为self,就完成了。

【讨论】:

  • 非常有帮助!好的,唯一的事情是我没有改变Stock 表,而是StockRelationship 表......这有点像Twitter 中的“关注”。所以,此时,StockRelationship 被创建,但是stock_idnil。我正在修改上面的代码来说明。
  • 好的,在上面的重构之后它可以工作了(因为我真的在处理 StockRelationship,所以做了一些调整):stock_relationships.create(stock_id: stock.id) 最终将 stock_id 添加到数据库中。
  • 对不起。我更新了我的答案。中国现在是 22:00,我有点困 :)
【解决方案2】:

你正在调用类的实例方法,你需要这样的东西。

#user.rb
def follow_stock(stock)
  self.stock_relationships.create(stock_id: stock)
end
#and from controller call it like
user.follow_stock(stock)

现在,您的方法变成了实例方法,您可以通过用户类的实例调用它。

【讨论】:

  • 在这种情况下我经常省略self.,但这只是一个人情问题。
  • @Aetherus,是的,这是选择的问题。
【解决方案3】:

stock_relationships 是在用户实例上定义的。看起来你正试图在你的模型中的 User 上调用它

self.stock_relationships.create(stock_id: stock)

【讨论】:

  • 所以我需要在StockController 中代替user = current_user.iduser = User.find(current_user.id) ?
  • @Godzilla74 用更窄的范围回答问题、修复错误并进入下一个问题会更容易
  • @nikkypx 这就是我想要做的......这是我遇到的第一个与此相关的错误。
猜你喜欢
  • 1970-01-01
  • 2013-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多