Railsアプリケーションプログラミングの勉強中です。
requireメソッドで別のファイルに書かれたプログラムをソース中に取り込みたいのですが、ファイルの置き場所と使い方について
どなたか教えていただけないでしょうか?
ファイル名を mylibrary.rb として細かいプログラムなどを記述してcustomerフォルダ内のscore_controller.rbで使用したいのですがcustomerフォルダにmylibrary.rbを格納すればいいのでしょうか?
また、mylibrary.rb内で作った変数は読み込んだscore_controller.rbで使用できるのでしょうか?
イメージはこんな感じです。
mylibrary.rb
customer = Customer.find_by(id: current_customer.id)
point = customer.point
・
・
・
score_controller.rb
require "mylibrary"
・
・
・
@sc1 = point + 100
・
・
のようにscore_controller.rbでmylibrary.rbファイルを読み込んで、mylibrary.rbで作った変数pointに100を加えてインスタンス変数に保存し表示する。簡単に記述すると以上のようなイメージです。mylibrary.rbの内容は少々複雑で長い記述となり、他でも同じ処理を使用するのでこのように別のファイルに記述しその部分を外部プログラムとして取り込みたいのです。
ファイルの置き場所と変数が使用できるのかについてどなたか教えていただけないでしょうか?
宜しくお願いします。
追記:mingosさんのおすすめコードについて
attr_reader :scoreのscoreとdef initialize(customer:)の(customer:)についてです。
attr_reader :scoreのscoreですが、mingosさんの例でいくとcommandテーブルのscoreカラムにアクセスするという意味になるのでしょうか?
def initialize(customer:)の(customer:)ですが(customer)と「:」の有無によって何が違ってくるのでしょうか?
もしよかったら教えていただけないでしょうか?宜しくお願いします。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+1
説明すべき事が多くて少し混乱させてしまうと思います。
疑問点をコメントでもらえればと思います。
rubyのクラスとインスタンス変数へのアクセスについて
こういうクラス定義があったすると、
MyClass.new.nameとは出来ないのは理解できますでしょうか?
@nameはインスタンス変数で、外部に対しては非公開だからですね。
class MyClass
# コンストラクタ
# MyClass.newとして使う
# メソッド名が異なる点に注意
# 違和感あるけどそういうものです
def initialize
@name = "あいうえお"
end
end
@nameを外部から取得できるようにするために、railsのモデル風にnameというメソッドを定義します。
いわゆるゲッターメソッドですね。
本当は名前は、なんでもよくてget_nameとかでもいいです。
後から出て来る、attr_xxx系の命令と動作を同じにするため=説明の都合上でこういう名前にしてます。
class MyClass
def initialize
@name = "あいうえお"
end
def name
@name
end
# ゲッターの名前は何でもいい
def get_name
@name
end
end
これとまったく同じことをするのが、attr_reader :nameです。
セッターも欲しいなという場合には、attr_accessor :nameとします。
本題はここからで、手で書いてもいいし、attr_xxxを使ってもいいので、MyClass.new.nameと出来るようにすれば、コントローラでも同じように使う事が出来ます。
独自クラスのインスタンス変数を他でも扱う事が出来るわけです。
置き場所について
rails5であれば、app/以下にあるファイルは自動でrequireしてくれます。
従って、app/lib/mylibrary.rbに置けば大丈夫です。
確認方法は、rails consoleでその処理が実行できるかどうかで確認できます。
ただし、クラスまたはモジュールにする必要があります。
app/helpers/にxxxx_helper.rbを定義して、コントローラでincludeする方法もあるんですけど、
カオスになりがちなので、独自クラスを作るほうを先に覚えたほうがいいと思って、そこだけ説明しますね。
たとえば、このようにただメソッドを定義しただけでは、
app/lib/mylibrary.rb
def sample
puts "sample"
end
このように認識されません。
$ rails console
> sample
NameError: undefined local variable or method `sample' for main:Object
from (irb):1
そこで、mylibrary.rbの内容をクラスにします。
ファイル名とクラス名は一致させる必要がある点に注意。
class Mylibrary
def sample
puts "sample"
end
end
クラスなので、当然newしてからメソッドを呼ぶ必要がありますが、
きちんと実行できました。
コンストラクタ(initialize)は独自の処理が必要なければ、書かなくてもいいです。
$ rails console
> Mylibrary.new.sample
sample
rails consoleで実行できることは、コントローラでも実行できます。
従って、いきなりコントローラに書かずにconsoleでいろいろ試すのが一番効率がいいです。
実行と結果の確認がすぐできるため。
ブラウザで開くより早いですよね。
コントローラでは、このよう同じように書けます。
rails consoleで実験してうまくいったら、コントローラでもそのまま書けば良いというのがポイントです。
class ScoreController < ApplicationController
def sample
Mylibrary.new.sample
あるいは、こうも書ける(文法上当たり前)
mylib = Mylibrary.new
mylib.sample
end
end
コントローラの変数をビューに渡す方法=画面に表示する方法について
基本ルールについて理解があやふやっぽいので、ここについても説明します。
- コントローラのインスタンス変数を定義する(インスタンス変数=@付きの変数の事)
- ビューではコントローラのインスタンス変数が使える
- <%= @変数 %>で表示できる
これだけです。
要は、コントローラのメソッド=アクションの中で@変数を作れば、対応するビューでも使えるよ、
というだけのシンプルなルールです。
class ScoreController < ApplicationController
def sample
# @mylibを定義したから、app/views/score/sample.html.erbでも@mylibが使える
@mylib = Mylibrary.new
# @customerを定義したから、ビューでも@cusotmerが使えるし
# @customer.scoreも使える
@customer = Customer.find(1)
# いきなり@scoreをビューで使いたければ、ここで定義する
@score = 13435
end
end
個人的におすすめの方法
個人的な方法なのでとりあえず紹介だけしておきます。
内容は分からなくても問題ないですが、余計に混乱させたらすみません・・・。
私はこの手のクラスをコマンドと呼称する派ですが、世間一般ではサービスと呼ぶ事が多いです。
ある1つの操作(ポイントを更新するなど)を単体でクラスにします。
私の場合は、コンストラクタ(new=initaialize)と、実行(run!)を必ず用意します。
コマンドはnewしてrunするという使い方で統一するというルールを自分の中で作っているため。
app/commands/update_score_command.rb
# スコアを特定のルールに従って更新するコマンド
#
# 使い方:
# customer = Customer.find(1)
# command = UpdateScoreCommand.new(customer: customer)
# command.run!
# score = command.score
#
class UpdateScoreCommand
# command.scoreとしたいので、getterだけ用意する
# command.score =1234とされてしまう事故は防ぎたいので
# attr_accessorは使わない
attr_reader :score
def initialize(customer:)
@customer = customer
@score = @customer.score
end
def run!
@score.sc1 = @customer.point + 100
@score.save!
end
end
class ScoreController < ApplicationController
def sample
@customer = Customer.find(params[:id])
command = UpdateScoreCommand.new(customer: @customer)
command.run!
@score = command.score
end
end
追記
追記:mingosさんのおすすめコードについて
attr_reader :scoreのscoreとdef initialize(customer:)の(customer:)についてです。
attr_reader :scoreのscoreですが、mingosさんの例でいくとcommandテーブルのscoreカラムにアクセスするという意味になるのでしょうか?
attr_reader :scoreは、以下のコードと同じ意味です。
class UpdateScoreCommand
def score
@score
end
end
コマンドクラスはrailsのモデルではありませんので、データベースのカラムとは関係がありません。
ここでは、UpdateScoreCommandという普通のクラスのインスタンス変数として@scoreを使っているだけです。
データベースと関係するのは、ActiveRecordあるいはApplicationRecordを継承したクラスのみです。
railsでは、app/models/以下にあるクラスになります。
def initialize(customer:)の(customer:)ですが(customer)と「:」の有無によって何が違ってくるのでしょうか?
もしよかったら教えていただけないでしょうか?宜しくお願いします。
rubyの文法で、名前付き引数とかキーワード引数などと呼ばれるものです。
このようにメソッドを定義した場合、必ず、メソッド名(customer: 値) という風に使わないとエラーとなります。
引数が2つ、3つとかになって来るとありがたみが出てきます。
普通のメソッドは引数の順番を覚えておかなければいけませんが、キーワード引数であれば、引数に名前がついているので順序は適当で良いです。
あまりいい例が思いつきませんが、
def sum(a:, b:)
a + b
end
# キーワード引数なら、引数の順序はばらばらでもいい。
puts sum(b: 10, a: 5)
puts sum(a: 30, b: 30)
これを使う理由は、コード自体が説明書になるからですね。
今回の例では引数が1つなので、メリットはありませんが、常にこう書いたほうが楽なので。
実際いろいろやってると、メソッドの引数が3つ、4つ、5つって事が出て来ると思います。
そうなると、順番を確認するために毎回メソッド定義を見なくてはいけないくてしんどいです。
例えば、コマンド引数を増やしてみます。
基本的には+100ですが、任意に追加するポイントを変更できるようにしたい・・と無理やり条件を考えてみます。
class UpdateScoreCommand
def initialize(customer:, add: 100)
@customer = customer
@score = customer.score
@add = add.to_i # 文字列とか来るかもしれないので、数値にする
end
def run!
@score.sc1 = @customer.point + @add
@score.save!
end
end
customer = Customer.find(1)
c = UpdateScoreCommand.new(customer: customer, add: 500)
c.run!
もし、キーワード引数を使わないとすると、こうですね。
class UpdateScoreCommand
def initialize(customer, add)
@customer = customer
@score = customer.score
@add = add.to_i
end
end
c = UpdateScoreCommand.new(customer, 500)
仕事でプログラミングをやっていると数年前に書いたものを修正したりすることがよくあるのですが、
その頃にはもう自分で書いたものでさえ覚えていません。
まずは、コードの全体を把握しなければいけませんが、各メソッドの詳細を見なくても、
たぶんこういう事をしているんだろうな、という想像が出来るコードであって欲しいのです。
c = UpdateScoreCommand.new(customer: customer, add: 500)
と
c = UpdateScoreCommand.new(customer, 500)
では、どっちが良いかという話なんですね。
時が経っていると、自分で書いたコードでありながら、500ってなんだよ?みたいな気持ちになります。
前者もベストとは思いませんが、addって書いてあるので、まぁ500を足すんだろうくらいの予想ができます。
クラス名もUpdateScore。。。って書いてあるし。
この単純な例では、どっちでも良いという思うかもしれませんが、実際のコードはもっと複雑です。
うーん、うまい説明が出来なくて申し訳ないんですが、将来自分が困らないために面倒でもキーワード引数を使っているわけです。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.11%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2017/10/04 12:33
2017/10/04 12:38
2017/10/04 13:57
2017/10/04 14:29
attr_readerの説明と、キーワード引数についてです。
2017/10/04 14:38