2016-03-11 33 views
1

我目前有一個Rails應用程序,它允許用戶創建一個組並允許其他用戶加入該組。組「創建者」是該組的所有者,並且任何加入請求的成員都是成員。我希望用戶能夠創建只有一個組,但屬於很多(我認爲我已經捕獲了這種關係,但我有點不確定)。我需要一些幫助來了解我需要做什麼才能在用戶頁面上顯示組關聯。我應該如何創建一個組「show」頁面,以及如何在用戶「show」頁面上顯示組成員身份?我得到了SO的幫助,並跟隨了Railscast關於自我指涉關係的指導,幫助指導我建立關係。Rails - 用於創建用戶組的控制器問題

在此示例中,組稱爲Cliqs,成員資格由has_many:through控制。我使用Devise作爲用戶模型。

澄清我的問題:我是否正在捕獲我正試圖建立的關係?我將如何去允許用戶查看他們所屬的組?

另外,我不確定組創建者是否作爲組的成員關聯。我如何在我的模型/控制器中表現這一點?

這裏是我的代碼:

組型號:

class Cliq < ActiveRecord::Base 
belongs_to :owner, class_name: 'User' 

has_many :members, through: :cliq_memberships, source: :user 
has_many :cliq_memberships 
end 

會員制模式:

class CliqMembership < ActiveRecord::Base 
belongs_to :cliq 
belongs_to :user 
end 

用戶模型:

class User < ActiveRecord::Base 
has_one :owned_group, foreign_key: 'owner_id', class_name: 'Group' 

has_many :cliqs, through: :cliq_memberships 
has_many :cliq_memberships 
. 
. 
. 
end 

組控制器:

class CliqsController < ApplicationController 

    def show 
     @cliq = Cliq.find(params[:id]) 
    end 

    def new 
     @cliq = Cliq.new(params[:id]) 
    end 

    def create 
     @cliq = Cliq.create(cliq_params) 
     if @cliq.save 
      redirect_to current_user 
     else 
      redirect_to new_cliq_path 
     end 
    end 

    def destroy 
    end 

    def cliq_params 
     params.require(:cliq).permit(:name, :cliq_id) 
    end 
end 

組成員控制器:

class CliqMembershipsController < ApplicationController 

    def create 
     @cliq = cliq.find(params[:cliq_id]) 
     if @cliq_membership.save = current_user.cliq_memberships.build(:cliq_id => params[:cliq_id]) 
      flash[:notice] = "Joined #{@cliq.name}" 
     else 
      #Set up multiple error message handler for rejections/already a member 
      flash[:notice] = "Not able to join Cliq." 
     end 
     redirect_to cliq_url 
    end 

    def destroy 
     @cliq = Cliq.find(params[:id]) 
     @cliq_memberships = current_user.cliq_memberships.find(params[cliq_memberships: :cliq_id]).destroy 
     redirect_to user_path(current_user) 
    end 
end 

我的用戶顯示頁面:

<h1> <%= @user.username %> </h1> 

<h2>Cliqs</h2> 

<%= link_to "Create Cliq", new_cliq_path %> 

<ul> 
    <% for cliq_membership in @user.cliq_memberships %> 
    <li> 
     <%= cliq_membership.cliq.name %> 
     (<%= link_to "Leave Cliq", cliq_membership, :method => :delete %>) 
    </li> 
    <% end %> 
</ul> 

<h3>Title:</h3> 
<% @uploads.each do |upload| %> 
    <div> 
     <%= link_to upload.title, upload_url %> 
    </div> 
<% end %> 

我的遷移:

Cliq手機:

class CreateCliqs < ActiveRecord::Migration 
    def change 
    create_table :cliqs do |t| 

     t.string :name 
     t.references :owner 
     t.integer :cliq_id 

     t.timestamps null: false 
    end 
    end 
end 

CliqMemberships:

class CreateCliqMemberships < ActiveRecord::Migration 
    def change 
    create_table :cliq_memberships do |t| 
     t.references :user 
     t.references :cliq 

     t.timestamps null: false 
    end 
    end 
end 

什麼BELOW全職工作解決方案。

+0

所以用戶和Cliqs之間有一個橋接表。對於我過去曾經參與過的項目,橋表中有一個「角色」列,表示用戶是管理員,用戶還是組的所有者。這種方法會在這裏工作嗎? – erapert

+0

我將如何去實施呢?我仍然對HMT協會感到困惑。 –

+0

HMT?你的意思是多對多的權利?許多用戶可以屬於很多組,對吧?唯一的限制是用戶只能_own_一個組,對吧? – erapert

回答

0

請嘗試以下操作:

您的修訂型號。修正了以下問題:

User模型,爲has_one :owned_group,設置class_nameGroup而不是Cliq

has_many :through之前聲明has_many。否則它可能會起作用,但這是一種很好的做法,易於閱讀。

class User < ActiveRecord::Base 
    has_one :owned_group, foreign_key: 'owner_id', class_name: 'Cliq' 
    has_many :cliq_memberships 
    has_many :cliqs, through: :cliq_memberships 
end 

class CliqMembership < ActiveRecord::Base 
    belongs_to :cliq 
    belongs_to :user 
end 

class Cliq < ActiveRecord::Base 
    belongs_to :owner, class_name: 'User' 
    has_many :cliq_memberships 
    has_many :members, through: :cliq_memberships, source: :user 
end 

您的修改控制器。修復了以下問題:

CliqsController中,因爲它與Cliq有關,創建它時不會得到​​。因此從cliq_params中刪除了​​。您可以在其中添加其他cliq相關屬性。

create中,您忘記指定current_user作爲cliq的所有者。這由下一個註釋解決。

由於usercliq的所有者,使用build_owned_group該選項自動設定current_user作爲所有者建cliq

儘量不要在同一語句中做多件事。就像將它分配給一個變量以及對新分配的變量進行一些操作一樣。例如:在create動作CliqMembershipsController中,您分配了@cliq_membership以及呼叫save就可以了。將這兩個分爲兩步。

destroyCliqMembershipsController,沒有必要加載@cliq並且還固定了你找到@cliq_membership的方式。

class CliqsController < ApplicationController 

    def show 
     @cliq = Cliq.find(params[:id]) 
    end 

    def new 
     @cliq = Cliq.new(params[:id]) 
    end 

    def create 
     @cliq = current_user.build_owned_group(cliq_params) 

     if @cliq.save 
      redirect_to current_user 
     else 
      redirect_to new_cliq_path 
     end 
    end 

    private 
    def cliq_params 
     params.require(:cliq).permit(:name) 
    end 
end 

class CliqMembershipsController < ApplicationController 

    def create 
     @cliq = Cliq.find(params[:cliq_id]) 
     @cliq_membership = current_user.cliq_memberships.build(cliq: @cliq) 

     if @cliq_membership.save 
     flash[:notice] = "Joined #{@cliq.name}" 
     else 
     #Set up multiple error message handler for rejections/already a member 
     flash[:notice] = "Not able to join Cliq." 
      redirect_to cliq_url 
     end 

    def destroy 
     @cliq_membership = current_user.cliq_memberships.find(params[:id]) 

     if @cliq_membership.destroy 
      redirect_to user_path(current_user) 
     end 
    end 
end 

最後修改後的看法:

固定的幾件事情。

嘗試使用集合上的each來迭代。這是更多ruby的方式,而不是for循環。

根據您的CliqMemberhipsController代碼,我認爲您使用的嵌套資源如下。因此修復了link_to以使用cliq_cliq_memberhip_path而不是cliq_membership_path

<h1><%= @user.username %></h1> 

<h2>Cliqs</h2> 

<%= link_to "Create Cliq", new_cliq_path %> 

<ul> 
    <% @user.cliq_memberships.each do |cliq_membership| %> 
     <li><%= cliq_membership.cliq.name %>(<%= link_to "Leave Cliq", cliq_cliq_membership_path([cliq, cliq_membership]), method: :delete %>)</li> 
    <% end %> 
</ul> 

這裏假設你有一個路線文件有以下:

resources :cliqs do 
    resources :cliq_memberships 
end 
+0

我很喜歡這個!但是我得到了一個「未知屬性:Cliq的'Owner_ID'」。 –

+0

以下是遷移:對於Cliq:def change create_table:cliqs do | t | t.string:命名 t.references:業主 t.integer:cliq_id t.timestamps空:假 –

+0

對於Cliq_Membership:DEF改變 CREATE_TABLE:cliq_memberships做| T | \t t.references:user \t t.references:cliq t.timestamps null:false –

0

按照我上面評論的觀點,我認爲最好的做法是在橋表中實現某種role屬性。

The Rails docs say this:

你應該使用的has_many:通過,如果你需要對連接模型驗證,回調,或額外的屬性。

所以你可能在你的模型試試這個:

class Cliq < ActiveRecord::Base 
    has_many :cliq_memberships 
    has_many :members, through: :cliq_memberships 

    def owner 
    cliq_memberships.where(role: 'owner').user 
    end 
end 

# this model is used to access attributes on the bridge table 
class CliqMembership < ActiveRecord::Base 
    belongs_to :cliq 
    belongs_to :user 

    attr_accessor :role 
end 

class User < ActiveRecord::Base 
    has_many :cliq_memberships 
    has_many :cliqs, through: :cliq_memberships 

    # something like this would make it easy to grab the owned cliq 
    def ownedCliq 
    cliq_memberships.where(role: 'owner').cliq 
    end 
end 

所以橋表存儲role這將是一個枚舉或代表「成員」的字符串,「所有者」,也許「管理員」或者其他的東西。

一些示例用法:

# say I have a user 
u = User.find(1) 
# and I want the cliq that he/she owns 
owned_cliq = u.ownedCliq 

# maybe I have a group: 
g = Cliq.find(1) 
# and I want the user that owns it: 
my_owner = g.owner 
# now let's get all the members of the cliq (including the 'owner') 
my_members = g.members 

更多示例用法:

# inside the controller... 

# say I have a user: 
u = User.find(1) 

# this user is trying to create a cliq 
# pretend we fill it in with its data here... 
c = Cliq.new 
c.save! 

# we'll need to hook the two together: 
cm = CliqMembership.new(role: 'owner', user_id: u.id, cliq_id: c.id) 
cm.save! 
# or we might try something like this: 
#cm = CliqMembership.find_or_create_by #... 

另外,我發現this SO answer這很好地解釋事情的一個好工作。

+0

我喜歡這樣看起來的樣子,因爲它將事情分開。我如何設置創建用戶是所有者?我將如何去讓其他用戶請求加入並在他們自己的頁面上顯示「組所屬」關係? –

+0

我明白你接近它的方式。目前,經過一些測試後,我瞭解到,使用我的代碼,創建用戶只能創建一個組(這很好)。當我在「user/show」頁面中放入「<%= @ user.cliq_memberships.name%>」時,所有顯示的都是「CliqMemberships」。看起來,用我的代碼,正在建立正確的關聯關係,但在呈現我想要的內容時存在一些問題。看起來好像「創建用戶」不是作爲成員持續存在的。我如何實現這一目標? –

+0

其實用戶可以創建多個組。驗證是否可以解決這個問題? –

0

於是我開始的代碼在我的問題上面,然後向內合作,我的回答(通過許多額外的試驗)。這可能有助於未來的人,所以這裏有用。 (從兩個答案採取建議):

class Cliq < ActiveRecord::Base 
belongs_to :owner, class_name: 'User' 

has_many :cliq_memberships 
has_many :members, through: :cliq_memberships, source: :user 
end 

class CliqMembership < ActiveRecord::Base 
belongs_to :cliq 
belongs_to :user 
end 

class User < ActiveRecord::Base 
has_one :owned_cliq, foreign_key: 'owner_id', class_name: 'Cliq' 

has_many :cliq_memberships 
has_many :cliqs, through: :cliq_memberships 
. 
. 
. 
end 

class CliqsController < ApplicationController 

    def show 
     @cliq = Cliq.find(params[:id]) 
    end 

    def new 
     @cliq = Cliq.new(params[:id]) 
    end 

    def create 
     @cliq = current_user.build_owned_cliq(cliq_params) 
     @cliq.members << current_user 

     if @cliq.save 
      redirect_to current_user 
     else 
      redirect_to new_cliq_path 
     end 
    end 

    def destroy 
    end 


    def cliq_params 
     params.require(:cliq).permit(:name, :cliq_id) 
    end 
end 

class UsersController < ApplicationController 

    def show 
     #find way to use username instead of id (vanity url?) 
     @user = User.find(params[:id]) 
     @uploads = Upload.all 
     @cliq_memberships = CliqMembership.all 
     @cliqs = Cliq.all 
    end 

end 

class CliqMembershipsController < ApplicationController 

    def show 
    end 

    def create 
     @cliq = Cliq.find(params[:cliq_id]) 

     @cliq_membership = current_user.cliq_memberships.build(cliq: @cliq) 

     if @cliq_membership.save 
      flash[:notice] = "Joined #{@cliq.name}" 
     else 
      #Set up multiple error message handler for rejections/already a member 
     flash[:notice] = "Not able to join Cliq." 
     end 
     redirect_to cliq_url 
    end 

    def destroy 
     @cliq_membership = current_user.cliq_membership.find(params[:id]) 

     if @cliq_membership.destroy 
     redirect_to user_path(current_user) 
    end 
end 

class CreateCliqs < ActiveRecord::Migration 
    def change 
    create_table :cliqs do |t| 

     t.string :name 
     t.references :owner 

     t.timestamps null: false 
    end 
    end 
end 

class CreateCliqMemberships < ActiveRecord::Migration 
    def change 
    create_table :cliq_memberships do |t| 
     t.references :user 
     t.references :cliq 

     t.timestamps null: false 
    end 
    end 
end 

非常感謝所有在這個線程的令人難以置信的幫助!