about 3 years ago

本章的作業目標:

  • 建立 討論版成員 ( group_user ) 設定
  • user 必須要是這個社團的成員才能發表文章
  • user 可以在 group 頁面 加入 / 退出 此 group
  • User 在建立 group 後自動成為 group 的一員
  • 若不是 group 創辦人,就不會顯示 edit 按鈕

建立 討論版成員 ( group_user ) 設定

rails g model group_user group_id:integer user_id:integer
新增一個叫 group_user 資料表, 裡面的欄位是 group_id 跟 user_id

rake db:migrate
執行資料庫異動設定

打開 app/models/user.rb

app/models/user.rb
...
...
  has_many :groups
  has_many :posts

+ has_many :group_users
+ has_many :participated_groups, through: :group_users, source: :group
end

打開 app/models/group.rb

app/models/group.rb
class Group < ActiveRecord::Base
  validates :title, presence: true

  has_many :posts
+ has_many :group_users
+ has_many :members, through: :group_users, source: :user
..
..

打開 app/models/group_user.rb

app/models/group_user.rb
class GroupUser < ActiveRecord::Base
+ belongs_to :user
+ belongs_to :group
end

解說

[延伸閱讀] Active Record Association


user 必須要是這個社團的成員才能發表文章

打開 ruby app/models/user.rb

app/models/user.rb
...
...
  has_many :group_users
  has_many :participated_groups, through: :group_users, source: :group

+ def is_member_of?(group)
+   participated_groups.include?(group)
+ end
end

打開 app/controllers/posts_controller.rb

app/controllers/posts_controller.rb
class PostsController < ApplicationController
 
  before_action :authenticate_user!
 
  before_action :find_group
  
+ before_action :member_required, only: [:new, :create ]
...
...
  private
..
..
+ def member_required
+   if !current_user.is_member_of?(@group)
+     flash[:warning] = "你不是這個討論版的成員,不能發文喔!"
+     redirect_to group_path(@group)
+   end
+ end
end

接下來要做出讓 user 可以加入退出 group 的功能


user 可以在 group 頁面 加入 / 退出 此 group

打開 app/models/user.rb

app/models/user.rb
class User < ActiveRecord::Base
...
...
+ def join!(group)
+   participated_groups << group
+ end
+
+ def quit!(group)
+   participated_groups.delete(group)
+ end

  def is_member_of?(group)
    participated_groups.include?(group)
  end
end

打開 app/controllers/groups_controller.rb

app/controllers/groups_controller.rb
...
...
+ def join
+   @group = Group.find(params[:id])
+
+   if !current_user.is_member_of?(@group)
+     current_user.join!(@group)
+     flash[:notice] = "加入本討論版成功!"
+   else
+     flash[:warning] = "你已經是本討論版成員了!"
+   end
+
+   redirect_to group_path(@group)
+ end
+
+ def quit
+   @group = Group.find(params[:id])
+
+   if current_user.is_member_of?(@group)
+     current_user.quit!(@group)
+     flash[:alert] = "已退出本討論版!"
+   else
+     flash[:warning] = "你不是本討論版成員,怎麼退出 XD"
+   end
+
+   redirect_to group_path(@group)
+ end

  private
 ...
 ...

打開 config/routes

config/routes
...
...
  resources :groups do
+   member do
+     post :join
+     post :quit
+   end

    resources :posts
  end
...
...

打開 app/views/groups/show.html.erb

app/views/groups/show.html.erb
...
...
  <div class="group">
    <%= link_to("New Post", new_group_post_path(@group), class: "btn btn-warning pull-right")%>
    <%= link_to("Edit", edit_group_path(@group), class: "btn btn-primary pull-right")%>
+   <% if current_user.present? %>
+     <% if current_user.is_member_of?(@group) %>
+       <%= link_to("Quit Group", quit_group_path(@group), method: :post, class: "btn btn-danger") %>
+     <% else %>
+       <%= link_to("Join Group", join_group_path(@group), method: :post, class: "btn btn-info") %>
+     <% end %>
+   <% end %>
 </div>
...
...


User 在建立 group 後自動成為 group 的一員

當你創辦了 group ,卻還要手動再加入這個 group 不會很怪嗎? XD

app/controllers/groups_controller.rb
...
...
  def create
    @group = current_user.groups.new(group_params)
  
    if @group.save 
+     current_user.join!(@group)
      redirect_to groups_path, notice: "新增討論版成功"
    else
      render :new
    end
  end
 ...
 ...

若不是 group 創辦人,就不會顯示 edit 按鈕

就算已經設定不是作者,按了 edit 也會跳 error
但不是作者還跑出 edit 來讓你按實在是很怪,對吧?

app/views/groups/show.html.erb
...
...
  <div class="group">
+   <% if @group.editable_by?(current_user) %>
      <%= link_to("Edit", edit_group_path(@group) , class: "btn btn-primary pull-right") %>
+   <% end %>
...
...


← [ 2.0 ] 4. 建立使用者功能 [ 2.0 ] 6 - 0. 實做簡單的後台機制 →
 
comments powered by Disqus