初めに
プログラミング学習初めて1ヶ月と少しです。 理解不足、誤りがありましたらご指摘いただけますと幸いです。グループ作成機能①
本の投稿サイトを作成しています。①の今回は、グループを作れるようにします。 この記事ではあるユーザーがグループを作る流れをまとめています。 グループに参加する機能は無いです。それは②でやります。今回の記事でできるようになること
*グループを作成するリンクの表示。 *グループを作れる。(②の記事でメンバー増やせるようにします) *作成した人はグループオーナー *グループ一覧画面作成。 *グループのオーナーであればグループの編集ができる *グループの詳細画面(①の段階では質素な画面です。)グループの編集は、グループの作成者のみが行えます。(削除機能は無しです。)
画面は以下の4つ。
グループ一覧画面。
グループ詳細画面。
グループ編集画面。
グループ作成画面。
「作成イメージ」
まずアソシエーション考える
ユーザー:Group= 1:N(複数) Group:ユーザー=1:N(複数) なので、中間テーブルが必要になります。 中間テーブルは、GroupUserとして、外部キーとしてuser_idとgroup_idを持たせます。Groupテーブルのカラムは
id
name
introduction
image_id (グループ画像も設定可能にします!)
owner_id (グループ作成者をowner_idにします)
作成開始
$ rails g model group
$ rails g model group_user```
中間テーブルであるgroup_userは何かするわけではなく、groupとユーザーの外部キーを持ってくれてるだけなので、コントローラーはいりません。
<h2>マイグレーションファイルの内容</h2>
```perl:20~~??_create_groups.rb
class CreateGroups < ActiveRecord::Migration[5.2]
def change
create_table :groups do |t|
t.string :name
t.text :introduction
t.string :image_id
t.integer :owner_id
t.timestamps
end
end
end
class CreateGroupUsers < ActiveRecord::Migration[5.2]
def change
create_table :group_users do |t|
t.references :user, index: true, foreign_key: true
t.references :group, index: true, foreign_key: true
t.timestamps
end
end
end
ここの記述は簡単にいうと、group_usersに外部キーとしてuser_idとgroup_idを登録しています。以下の記事がわかりやすかったです。reference使えば、自動でindexもひっぱってくるということなので、index:true
はなくても良いようです。
忘れずにマイグレーション!
rails db:migrate
モデルファイルにアソシエーション記述
グループの削除機能はないので、dependent: :destroyの記述はないです。
class GroupUser < ApplicationRecord
belongs_to :user
belongs_to :group
end
class Group < ApplicationRecord
has_many :group_users
has_many :users, through: :group_users
validates :name, presence: true
validates :introduction, presence: true
attachment :image, destroy: false
end
現状、destroy:falseがわかりませんdestroyはできない という意味なのでしょうか。
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :books
has_many :group_users #ここ!
has_many :groups, through: :group_users
has_many :favorites, dependent: :destroy
has_many :book_comments, dependent: :destroy
attachment :profile_image, destroy: false
validates :name, length: { minimum: 2, maximum: 20 }, uniqueness: true
validates :introduction, length: { maximum: 50 }
end
has_many :groups, through: :group_users
これは、userは、group_usersという中間テーブルを通じてgroupsにアクセスできるという記述。
Userのボス「そりゃーグループの情報掴めるよ〜group_usersを通じて聞けばいいんだよ」みたいな。group_usersさんは仲介役ですね。
なんだか、ちんぷんかんだった中間テーブルがわかってきたような気がします。
Userのボスからしてみても、中間テーブルという仲介役がいた方がラクなんですよね。
ルーティングの設定
resources :groups, except: [:destroy]
もちろん
```のような記述でもいけると思います。
<h2>コントローラー作成</h2>
```perl:groups_controller.rb
class GroupsController < ApplicationController
before_action :authenticate_user!
before_action :ensure_correct_user, only: [:edit, :update]
def index
@book = Book.new
@groups = Group.all
end
def show
@book = Book.new
@group = Group.find(params[:id])
end
def new
@group = Group.new
end
def create
@group = Group.new(group_params)
@group.owner_id = current_user.id
if @group.save
redirect_to groups_path
else
render 'new'
end
end
def edit
end
def update
if @group.update(group_params)
redirect_to groups_path
else
render "edit"
end
end
private
def group_params
params.require(:group).permit(:name, :introduction, :image)
end
def ensure_correct_user
@group = Group.find(params[:id])
unless @group.owner_id == current_user.id
redirect_to groups_path
end
end
end
本の投稿サイトなので、@book等の記述も入ってしまっています。
Viewページ
<div><%=link_to "グループを作成する",new_group_path %> | <%=link_to "グループ一覧",groups_path %></div>
その他のview
部分テンプレートで飛ばしています。
<div class='container'>
<div class='row'>
<div class="col-sm-12 col-md-8 col-lg-5 px-5 px-sm-0 mx-auto">
<h3>Editing Group</h3>
<%= render 'form', group: @group %>
</div>
</div>
<%= form_with model: group, local: true do |f| %>
<div class="form-group">
<%= f.label :グループ名 %>
<%= f.text_field :name, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :紹介文 %>
<%= f.text_area :introduction, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :グループ画像 %>
<%= f.attachment_field :image, class: "form-control-file" %>
</div>
<div class="form-group">
<%= f.submit class: 'btn btn-info' %>
</div>
<% end %>
#関連部分のみ
<div class='col-md-8 offset-md-1'>
<h2>Groups</h2>
<table class='table table-hover table-inverse'>
<thead>
<tr>
<th></th>
<th>グループ名</th>
<th>紹介文</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @groups.each do |group| %>
<tr>
<td><%= attachment_image_tag(group, :image, :fill, 50, 50, fallback: "no-image-icon.jpg") %></td>
<td><%= link_to group.name, group_path(group) %></td>
<td><%= group.introduction %></td>
<td>
<% if group.owner_id == current_user.id %>
<%= link_to 'Edit', edit_group_path(group), class: "btn btn-sm btn-success" %>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
<div class='container'>
<div class='row'>
<div class="col-sm-12 col-md-8 col-lg-5 px-5 px-sm-0 mx-auto">
<h3>Create Group</h3>
<%= render 'form', group: @group %>
</div>
</div>
</div>
<div class='container px-5 px-sm-0'>
<div class='row'>
<div class='col-md-3'>
<h2>User info</h2>
<%= render 'users/info', user: current_user %>
<h2 class="mt-3">New book</h2>
<%= render 'books/form', book: @book %>
</div>
<div class='col-md-8 offset-md-1'>
<h2>Group Detail</h2>
<table class='table table-hover table-inverse'>
<tr>
<td><%= attachment_image_tag(@group, :image, :fill, 50, 50, fallback: "no-image-icon.jpg") %></td>
<td><%= @group.name %></td>
<td><%= @group.introduction %></td>
<td>
<% if @group.owner_id == current_user.id %>
<%= link_to 'Edit', edit_group_path(@group), class: "btn btn-sm btn-success" %>
<% end %>
</td>
</tr>
</table>
</div>
</div>
</div>