[Ruby on Rails]Rails Engine – (2)サブプロジェクトにてメインプロジェクトのModelを使用する

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

前回に引き続きRails Engineについてです。タイトル通り、サブプロジェクトにてメインプロジェクトのModelを使用する方法です。メインのプロジェクトとサブプロジェクトは関係がある以上、このような方法は必ず必要になってくるかと思います。

今回作成するサンプルの概要

前回作成したメインプロジェクト・サブプロジェクトに、ユーザを追加します。メインプロジェクトにユーザのModelを持ち、サブプロジェクト側では記事の登録時にユーザModelを参照し、入力されたユーザが存在すればそのIDを、存在しない場合はユーザを新規に作成します。

サンプルの作成手順

基本的には公式サイトの手順通りですが、一部変えて実行したところもあります。では、手順です。

1.ユーザModelの作成

メインプロジェクト側にユーザModelを作成します。

$ bundle exec rails g model user name:string

rake db:migrateでDBにユーザテーブルを作成します。

2.記事登録時にユーザを登録する

サブプロジェクトのapp/views/blorgh/articles/_form.html.erbに、記事登録時にユーザ名を入力する欄を追記します。

<div class="field">
  <%= f.label :author_name %><br>
  <%= f.text_field :author_name %>
</div>

ユーザ名のフィールド名は「author_name」であることに注意して下さい(後ほどユーザとauthor_nameの紐付けはします)。

app/controllers/blorgh/articles_controller.rbのarticle_paramsメソッドを修正し、author_nameをフォームから取得できるようにします。

def article_params
  params.require(:article).permit(:title, :text, :author_name)
end

記事のModelであるapp/models/blorgh/article.rbを修正し、記事登録時にユーザを登録できるようにします。

attr_accessor :author_name
belongs_to :author, class_name: "User"
 
before_save :set_author
 
private

def set_author
  self.author = User.find_or_create_by(name: author_name)
end

「belongs_to :author, class_name: "User"」でユーザとauthorの紐付けをしています。「User.find_or_create_by(name: author_name)」でフォームのユーザ名からユーザを検索し、存在していれば取得、無ければ登録をしています。同じ行の「self.author」に代入することで、ユーザのidが記事Modelの「author_id」に登録されます。

マイグレーションを実行し、記事のテーブルにユーザを登録するカラムを追加します。ユーザ名ではなく「id」であることに注意してください。

$ bundle exec rails g migration add_author_id_to_blorgh_articles author_id:integer

rake db:migrateを行い、author_idをArticleテーブルに追加します。ここまではサブプロジェクトでの作業でした。

3.メインプロジェクトにマイグレーションを反映する

先に記事のModelに行った変更を、メインプロジェクトでも行う必要があります。ここが公式サイトとは違うのですが、サブプロジェクトでマイグレーションを行った時に作成されたファイルを、メインプロジェクトにコピーしました。(バッドノウハウかもしれないです・・・)

cp ルートディレクトリ/blorgh/test/dummy/db/migrate/タイムスタンプ_add_author_id_to_blorgh_articles.rb ルートディレクトリ/blorgh-parent/db/migrate

rake db:migrateを行い、メインプロジェクトにもマイグレーションを行います。

4.ユーザ名の表示

記事の登録時に入力したユーザ名を表示できるよう、サブプロジェクトとメインプロジェクトを修正します。

サブプロジェクトのapp/views/blorgh/articles/show.html.erbに以下を追加し、記事を作成したユーザ名を表示します。

<p>
  <b>Author:</b>
  <%= @article.author %>
</p>

ユーザ名が表示されるよう、メインプロジェクトのblorgh-parent/app/models/user.rbに以下を追記します。

def to_s
  name
end

最後にメインプロジェクトにてRailsを実行し、記事登録時にユーザ名を登録できること、また記事表示時にはユーザ名が表示されることを確認してみてください。

まとめ

サブプロジェクト側からは特に意識することなく、メインプロジェクト側のModelを使用することができました。マイグレーションをどちらのプロジェクトで行うのかに注意すればいいかと思います。

参考サイト

Getting Started with Engines
Rails エンジン入門(日本語)