我目前有一个Rails应用程序,允许用户创建一个组并允许其他用户加入该组。组“创建者”是组的所有者,任何加入ON REQUEST的组织都是成员。我希望用户能够只创建一个组,但属于许多组(我认为我已经捕获了这种关系,但我有点不确定)。我需要一点帮助,了解我需要做什么才能在用户页面上显示组关联。我应该如何创建组“显示”页面,如何在用户“显示”页面上显示组成员身份?我得到了SO的帮助,并按照Railscast进行了自我指导协会,以帮助指导我建立关系。
在此示例中,组称为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
完全解决以下问题。
答案 0 :(得分:0)
在上面的评论中,我认为最好的办法是在桥接表中实现某种role
属性。
如果您需要在连接模型上进行验证,回调或额外属性,则应使用has_many:through。
所以你可以在模特中试试这个:
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
,它将是一个枚举或代表'member','owner',或者'admin'或其他东西的字符串。
一些示例用法:
# 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可以很好地解释事情。
答案 1 :(得分:0)
尝试以下方法:
您修改的模型。修正了以下问题:
在User
模型中,对于has_one :owned_group
,您将class_name
设置为Group
而不是Cliq
。
在has_many
之前声明has_many :through
。它可能会起作用,但这是一种很好的做法,易于阅读。
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_id
。已删除cliq_id
中的cliq_params
。您可以在其中添加其他cliq
相关属性。
在create
,您忘记将current_user
指定为cliq
的所有者。这将在下一个注释中解决。
由于user
是cliq
的所有者,使用cliq
构建了build_owned_group
,current_user
会自动将create
设置为所有者。
尽量不要在同一个语句中做多件事。就像将它分配给变量以及对新分配的变量进行一些操作一样。例如:在CliqMembershipsController
的{{1}}操作中,您分配了@cliq_membership
以及在其上调用save
。将这两者分成两步。
在destroy
的{{1}}中,无需加载CliqMembershipsController
,也可以修复找到@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>
答案 2 :(得分: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
非常感谢这个线程上所有令人难以置信的帮助!