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

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

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

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

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

Q&A

解決済

1回答

4087閲覧

Railsで外部プログラムを取り込むにはどうすればいいのでしょうか?

koume

総合スコア458

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

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

0グッド

0クリップ

投稿2017/10/03 23:20

編集2017/10/04 03:52

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)と「:」の有無によって何が違ってくるのでしょうか?
もしよかったら教えていただけないでしょうか?宜しくお願いします。

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

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

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

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

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

guest

回答1

0

ベストアンサー

説明すべき事が多くて少し混乱させてしまうと思います。
疑問点をコメントでもらえればと思います。

rubyのクラスとインスタンス変数へのアクセスについて

こういうクラス定義があったすると、
MyClass.new.nameとは出来ないのは理解できますでしょうか?
@nameはインスタンス変数で、外部に対しては非公開だからですね。

ruby

1class MyClass 2 3 # コンストラクタ 4 # MyClass.newとして使う 5 # メソッド名が異なる点に注意 6 # 違和感あるけどそういうものです 7 def initialize 8 @name = "あいうえお" 9 end 10 11end

@nameを外部から取得できるようにするために、railsのモデル風にnameというメソッドを定義します。
いわゆるゲッターメソッドですね。
本当は名前は、なんでもよくてget_nameとかでもいいです。
後から出て来る、attr_xxx系の命令と動作を同じにするため=説明の都合上でこういう名前にしてます。

ruby

1class MyClass 2 3 def initialize 4 @name = "あいうえお" 5 end 6 7 def name 8 @name 9 end 10 11 # ゲッターの名前は何でもいい 12 def get_name 13 @name 14 end 15 16end

これとまったく同じことをするのが、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

ruby

1def sample 2 puts "sample" 3end

このように認識されません。

$ rails console > sample NameError: undefined local variable or method `sample' for main:Object from (irb):1

そこで、mylibrary.rbの内容をクラスにします。
ファイル名とクラス名は一致させる必要がある点に注意。

ruby

1class Mylibrary 2 def sample 3 puts "sample" 4 end 5end

クラスなので、当然newしてからメソッドを呼ぶ必要がありますが、
きちんと実行できました。
コンストラクタ(initialize)は独自の処理が必要なければ、書かなくてもいいです。

$ rails console > Mylibrary.new.sample sample

rails consoleで実行できることは、コントローラでも実行できます。
従って、いきなりコントローラに書かずにconsoleでいろいろ試すのが一番効率がいいです。
実行と結果の確認がすぐできるため。
ブラウザで開くより早いですよね。

コントローラでは、このよう同じように書けます。
rails consoleで実験してうまくいったら、コントローラでもそのまま書けば良いというのがポイントです。

ruby

1class ScoreController < ApplicationController 2 3 def sample 4 Mylibrary.new.sample 5 あるいは、こうも書ける(文法上当たり前) 6 mylib = Mylibrary.new 7 mylib.sample 8 end 9 10end

コントローラの変数をビューに渡す方法=画面に表示する方法について

基本ルールについて理解があやふやっぽいので、ここについても説明します。

  • コントローラのインスタンス変数を定義する(インスタンス変数=@付きの変数の事)
  • ビューではコントローラのインスタンス変数が使える
  • <%= @変数 %>で表示できる

これだけです。
要は、コントローラのメソッド=アクションの中で@変数を作れば、対応するビューでも使えるよ、
というだけのシンプルなルールです。

ruby

1class ScoreController < ApplicationController 2 3 def sample 4 # @mylibを定義したから、app/views/score/sample.html.erbでも@mylibが使える 5 @mylib = Mylibrary.new 6 7 # @customerを定義したから、ビューでも@cusotmerが使えるし 8 # @customer.scoreも使える 9 @customer = Customer.find(1) 10 11 # いきなり@scoreをビューで使いたければ、ここで定義する 12 @score = 13435 13 end 14 15end

個人的におすすめの方法

個人的な方法なのでとりあえず紹介だけしておきます。
内容は分からなくても問題ないですが、余計に混乱させたらすみません・・・。
私はこの手のクラスをコマンドと呼称する派ですが、世間一般ではサービスと呼ぶ事が多いです。
ある1つの操作(ポイントを更新するなど)を単体でクラスにします。
私の場合は、コンストラクタ(new=initaialize)と、実行(run!)を必ず用意します。
コマンドはnewしてrunするという使い方で統一するというルールを自分の中で作っているため。

app/commands/update_score_command.rb

ruby

1# スコアを特定のルールに従って更新するコマンド 2# 3# 使い方: 4# customer = Customer.find(1) 5# command = UpdateScoreCommand.new(customer: customer) 6# command.run! 7# score = command.score 8# 9class UpdateScoreCommand 10 # command.scoreとしたいので、getterだけ用意する 11 # command.score =1234とされてしまう事故は防ぎたいので 12 # attr_accessorは使わない 13 attr_reader :score 14 15 def initialize(customer:) 16 @customer = customer 17 @score = @customer.score 18 end 19 20 def run! 21 @score.sc1 = @customer.point + 100 22 @score.save! 23 end 24end

ruby

1class ScoreController < ApplicationController 2 3 def sample 4 @customer = Customer.find(params[:id]) 5 command = UpdateScoreCommand.new(customer: @customer) 6 command.run! 7 8 @score = command.score 9 end 10 11end

追記

追記:mingosさんのおすすめコードについて

attr_reader :scoreのscoreとdef initialize(customer:)の(customer:)についてです。
attr_reader :scoreのscoreですが、mingosさんの例でいくとcommandテーブルのscoreカラムにアクセスするという意味になるのでしょうか?

attr_reader :scoreは、以下のコードと同じ意味です。

ruby

1class UpdateScoreCommand 2 def score 3 @score 4 end 5end

コマンドクラスはrailsのモデルではありませんので、データベースのカラムとは関係がありません。
ここでは、UpdateScoreCommandという普通のクラスのインスタンス変数として@scoreを使っているだけです。

データベースと関係するのは、ActiveRecordあるいはApplicationRecordを継承したクラスのみです。
railsでは、app/models/以下にあるクラスになります。

def initialize(customer:)の(customer:)ですが(customer)と「:」の有無によって何が違ってくるのでしょうか?

もしよかったら教えていただけないでしょうか?宜しくお願いします。

rubyの文法で、名前付き引数とかキーワード引数などと呼ばれるものです。
このようにメソッドを定義した場合、必ず、メソッド名(customer: 値) という風に使わないとエラーとなります。
引数が2つ、3つとかになって来るとありがたみが出てきます。
普通のメソッドは引数の順番を覚えておかなければいけませんが、キーワード引数であれば、引数に名前がついているので順序は適当で良いです。

あまりいい例が思いつきませんが、

ruby

1def sum(a:, b:) 2 a + b 3end 4 5# キーワード引数なら、引数の順序はばらばらでもいい。 6puts sum(b: 10, a: 5) 7puts sum(a: 30, b: 30)

これを使う理由は、コード自体が説明書になるからですね。
今回の例では引数が1つなので、メリットはありませんが、常にこう書いたほうが楽なので。
実際いろいろやってると、メソッドの引数が3つ、4つ、5つって事が出て来ると思います。
そうなると、順番を確認するために毎回メソッド定義を見なくてはいけないくてしんどいです。

例えば、コマンド引数を増やしてみます。
基本的には+100ですが、任意に追加するポイントを変更できるようにしたい・・と無理やり条件を考えてみます。

ruby

1class UpdateScoreCommand 2 3 def initialize(customer:, add: 100) 4 @customer = customer 5 @score = customer.score 6 @add = add.to_i # 文字列とか来るかもしれないので、数値にする 7 end 8 9 def run! 10 @score.sc1 = @customer.point + @add 11 @score.save! 12 end 13end 14 15customer = Customer.find(1) 16c = UpdateScoreCommand.new(customer: customer, add: 500) 17c.run!

もし、キーワード引数を使わないとすると、こうですね。

ruby

1class UpdateScoreCommand 2 3 def initialize(customer, add) 4 @customer = customer 5 @score = customer.score 6 @add = add.to_i 7 end 8end 9 10c = UpdateScoreCommand.new(customer, 500)

仕事でプログラミングをやっていると数年前に書いたものを修正したりすることがよくあるのですが、
その頃にはもう自分で書いたものでさえ覚えていません。
まずは、コードの全体を把握しなければいけませんが、各メソッドの詳細を見なくても、
たぶんこういう事をしているんだろうな、という想像が出来るコードであって欲しいのです。

ruby

1c = UpdateScoreCommand.new(customer: customer, add: 500)

c = UpdateScoreCommand.new(customer, 500)

では、どっちが良いかという話なんですね。
時が経っていると、自分で書いたコードでありながら、500ってなんだよ?みたいな気持ちになります。
前者もベストとは思いませんが、addって書いてあるので、まぁ500を足すんだろうくらいの予想ができます。
クラス名もUpdateScore。。。って書いてあるし。
この単純な例では、どっちでも良いという思うかもしれませんが、実際のコードはもっと複雑です。
うーん、うまい説明が出来なくて申し訳ないんですが、将来自分が困らないために面倒でもキーワード引数を使っているわけです。

投稿2017/10/04 01:41

編集2017/10/04 05:26
mingos

総合スコア4025

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

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

koume

2017/10/04 03:33

わかりやすく丁寧な回答ありがとうございます。練習でapp/lib/mylibrary.rbにいろいろ記述しコンソールで試してみます。質問させていただいてもよろしいでしょうか?質問内容に追記させていただきます。
mingos

2017/10/04 03:38

はい、質問してもらって大丈夫です。
koume

2017/10/04 04:57

ありがとうございます。追記させていただきましたので教えてください。宜しくお願いします。
mingos

2017/10/04 05:29

こちらも追記しました。 attr_readerの説明と、キーワード引数についてです。
koume

2017/10/04 05:38

とても良くわかりました。100回以上質問させていただいておりますが、ここまで丁寧に回答をいただいたのは初めてでものすごく感動しています。未熟者で単純な質問に対して親切に回答をしてくださりありがとうございます。今後とも宜しくお願いします。本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問