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

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

ただいまの
回答率

90.50%

  • Ruby

    7680questions

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

  • Ruby on Rails

    7277questions

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

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

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 443

koume

score 202

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ページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

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

 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。。。って書いてあるし。
この単純な例では、どっちでも良いという思うかもしれませんが、実際のコードはもっと複雑です。
うーん、うまい説明が出来なくて申し訳ないんですが、将来自分が困らないために面倒でもキーワード引数を使っているわけです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/04 12:33

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

    キャンセル

  • 2017/10/04 12:38

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

    キャンセル

  • 2017/10/04 13:57

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

    キャンセル

  • 2017/10/04 14:29

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

    キャンセル

  • 2017/10/04 14:38

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

    キャンセル

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

  • ただいまの回答率 90.50%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Ruby

    7680questions

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

  • Ruby on Rails

    7277questions

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