質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

3回答

6883閲覧

Rails、コントローラーでモデルのメソッドの呼び出し方がわからないです。

s_tatsuki

総合スコア44

Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

0グッド

0クリップ

投稿2019/03/28 15:29

編集2019/03/29 05:11

#質問内容
controllerからmodelのメソッドを参照する際、トピックcontroller7行目でトピックmodelのメソッドを呼び出せないのはなぜでしょうか?
#なぜこの質問をするのか(質問の背景)
adminというメソッドをmodelに定義してコントローラーから使いたいから。
controllerの条件式をメソッド化することで見る側の負荷を減らすために、簡単なコードにしたい。
#自分が思う仮説(私はこう思っている)
エラー文で未定義のメソッドと出てきたので、model側でのメソッドの定義の仕方に問題があるのではないかと思っているのですがどうでしょうか?

controller

1 def destroy 2 @topic = Topic.find_by(id: params[:id]) 3 @topic.destroy 4 flash[:notice] = "トピックを削除しました" 5 if admin 6 redirect_to(admin_path) 7 else 8 redirect_to("/") 9 end 10 end

model

1class Topic < ApplicationRecord 2 paginates_per 5 3 4 validates :title, {presence: true, length: {maximum: 40}} 5 validates :content, {presence: true, length: {maximum: 180}} 6 7 belongs_to :user 8 has_many :comments 9 10 def admin 11 @current_user.admin_status == true 12 end 13end

##追記:修正後の現状で躓いている点
ApplicationController↓

class ApplicationController < ActionController::Base before_action :set_current_user def set_current_user @current_user = User.find_by(id: session[:user_id]) end end

topicコントローラー↓

def destroy @topic = Topic.find_by(id: params[:id]) @topic.destroy flash[:notice] = "トピックを削除しました" if @current_user.admin redirect_to(admin_path) else redirect_to("/") end end

userモデル↓

class User < ApplicationRecord has_secure_password validates :name, {presence: true} validates :email, {presence: true, uniqueness: true} VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+.[a-z]+\z/i validates :email, presence: true, uniqueness: true, format: { with: VALID_EMAIL_REGEX ,message: "形式が間違っています" } has_many :topics has_many :comments def admin @current_user.admin_status == true end end

としています。
呼び出し方としてUserクラスにadminという
インスタンスメソッドを定義しています。
ApplicationControllerのbefore_actionで定義されている、@current_userを使い定義し実行しました。しかし今度は

@current_user.admin_status == true

でNoMethodErrorが発生してしまいます。。。
何がいけないのでしょうか?;;

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

asm

2019/03/29 02:08

adminであるかはTopicが関係する事なのでしょうか? もっといえば、@current_userってTopicのインスタンス変数なのですか?
s_tatsuki

2019/03/29 04:36

``` class ApplicationController < ActionController::Base before_action :set_current_user def set_current_user @current_user = User.find_by(id: session[:user_id]) end ``` に定義しています
guest

回答3

0

ベストアンサー

果たして、adminメソッドはTopicクラスもしくはインスタンスに関連の深いメソッドなのでしょうか?

追記を見るにControllerのインスタンス変数@current_userがadminかどうかを判断するもののようなので
Topicクラスに追加すべきメソッドには思えません。

質問者さんが欲しいのはヘルパーメソッドと呼ばれるものだと思います。

ruby

1# app/helpers/application_helper.rb 2module ApplicationHelper 3 # rubyの慣習として、真偽値を返すようなメソッドの末尾には`?`をつけると読みやすい 4 def admin? 5 current_user&.admin_status == true 6 end 7 8 # ApplicationControllerに置いた場合、Viewで使えない事もありそう 9 def current_user 10 @current_user ||= User.find_by(id: session[:user_id]) if session[:user_id] 11 end 12end

インスタンス変数は基本的に同じクラスの同じインスタンスでのみ共有している変数です。
(Railsのコントローラーとビューが例外なのでRailsしかやらないと納得しづらいのかもしれませんが)

コントローラーで設定したインスタンス変数がモデルクラス内で参照できたりはしません。

投稿2019/03/29 06:05

asm

総合スコア15147

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

現在記述されているTopicモデル内のadminメソッドはインスタンスメソッドなので、インスタンスからしか使用できません。

@topicにTopicクラスのインスタンスが入っている場合

Ruby

1@topic.admin

という形で利用します。

クラスメソッドにするならば
Topicクラス内で

Ruby

1def self.admin 2 // 処理 3end

と記述すると、

Ruby

1Topic.admin

で利用出来ます。

投稿2019/03/28 22:39

ReiLeiLei1025

総合スコア236

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

s_tatsuki

2019/03/29 01:44

回答ありがとうございます!検証してまいります!
guest

0

まず、adminをモデルで定義しているのであれば、Topicモデルで定義しているならばTopic.adminとする必要があると思います。クラス定義でdef self.~などとしていれば話は別ですが...。それ以上は、モデルのバリデーションファイルを見ないと分からないです汗

また、redirect_toの括弧は必要ないので、redirect_to admin_pathで良いと思います。
elseの場合に関しても同様に、redirect_to root_urlなどとするのが良いかと思います。

また、コントローラを少しでも省略して見やすくしたい場合には、あくまで提案ですがビューのDeleteボタンの部分を

<%= link_to "Delete", topic, method: :delete, data: { confirm: :"Are you OK?" }, class: 'btn btn-danger btn-xs' %>

などとして、Topicのdef destroyの最初の一行の@topic = Topic.find_by(id: params[:id])を削除して、@topic.destroyから始めれば良いかと思います。

投稿2019/03/28 15:52

bamboo-nova

総合スコア1408

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

s_tatsuki

2019/03/29 01:44

回答ありがとうございます!検証してまいります!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問