2016-07-14 6 views
0

コントローラの代わりにモデルにDBに影響を及ぼし、動作させるのが難しい機能をオフロードするという概念にはかなり新しくなっています。コントローラ内の他のモデルのメソッドの呼び出し

基本的に私の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' 

を、ここで私が持っているものです。

A user adds a stock in 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 %> 

Which then triggers the StockController add_stock method:

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 

The 3rd line in the method is where my problem is, since the follow_stock method resides in the User model:

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 

は、いくつかのいずれかを助けることができます私は実際にどのように私の頭を包んでこのメソッドを呼び出すか、私はそれを試している方法で完全に基盤を離れていますか?

UPDATE

私は周りにいくつかのコードを変更しましたし、今私はStockRelationshipしかし、stock_idnilとして保存されて作成することができています:

=> #<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 
+0

'#stock_relationships'はインスタンスメソッドであり、' User'クラスでは呼び出していますが、 'User'インスタンスでは呼び出さない、つまり問題です。 'def self.follow_stock(stock)'を 'def follow_stock(stock)'に変更してください。そして、 'user.follow_stock(stock) 'のように' StockController'に 'user = current_user.id'の代わりに –

答えて

0

リファクタリングによって徐々にコードを簡潔にすることができます。

まずは、コントローラに実装を書いてみましょう:あまりにも多くのコードではありません、と十分に簡潔である

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

を。私の意見では、私は、コードをリファクタリングを必要とは思わないが、あなたは

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

のように、表現力を高めるために、Userモデルにロジックを置くことを主張するならば、我々はUser#follow_stockを実装する必要があります。通知#を表記に使用しました。つまり、follow_stockはクラスメソッドではなくインスタンスメソッドにする必要があります。

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

私は(。悪?ないリファクタリング段階で)いくつかのコピー&ペーストをした、とselfcurrent_userを交換し、そしてそれが行われています。

+0

非常に役に立ちました!わかりました。唯一のことは、 'Stock'テーブルを変更していないということです。代わりに' StockRelationship'テーブルです...これはTwitterで「follow」と似ています。したがって、この時点で 'StockRelationship'が作成されますが、' stock_id'は 'nil'です。私は説明するために上記のコードを修正しています。 – Godzilla74

+0

申し訳ありません、上記のリファクタリングの後で働いています(StockRelationshipを実際に扱っているので、いくつかの調整が必要です)。 'stock_relationships.create(stock_id:stock.id)'は、DBにstock_idを追加します。 – Godzilla74

+0

申し訳ありません。私は自分の答えを更新しました。それは22:00中国で今、私は少し眠いです:) – Aetherus

0

stock_relationshipsは、ユーザー。ここにあなたのモデルのユーザーの上でそれを呼び出そうとしているようです。

self.stock_relationships.create(stock_id: stock) 
+0

と呼びます。' user = User.find(current_user.id) '? – Godzilla74

+0

@ Godzilla74あなたのコードには根本的な問題が多すぎます。 –

+0

@ArupRakshitまあ、それは役に立つコメントです。 – Godzilla74

0

このクラスでインスタンスメソッドを呼び出す場合、このようなものが必要です。

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

ここで、メソッドは、ユーザークラスのインスタンスによって呼び出すことができるインスタンスメソッドになります。

+0

このような場合に私はしばしば 'self.'を省略しますが、それはただの問題です。 – Aetherus

+0

@Aetherus、ええ、それは選択の問題です。 – power

関連する問題