Rails 4 应用程序:如何让用户邀请其他用户在特定模型实例上进行协作?
Rails 4 app: how to allow users to invite other users to collaborate on a particular model instance?
在我们的Rails4 app中,有四种模式:
class User < ActiveRecord::Base
has_many :administrations, dependent: :destroy
has_many :calendars, through: :administrations
end
class Administration < ActiveRecord::Base
belongs_to :user
belongs_to :calendar
end
class Calendar < ActiveRecord::Base
has_many :administrations, dependent: :destroy
has_many :users, through: :administrations
has_many :posts, dependent: :destroy
end
class Post < ActiveRecord::Base
belongs_to :calendar
end
以下是相应的迁移:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :first_name
t.string :last_name
t.string :email
t.integer :total_calendar_count
t.integer :owned_calendar_count
t.timestamps null: false
end
end
end
class CreateAdministrations < ActiveRecord::Migration
def change
create_table :administrations do |t|
t.references :user, index: true, foreign_key: true
t.references :calendar, index: true, foreign_key: true
t.string :role
t.timestamps null: false
end
end
end
class CreateCalendars < ActiveRecord::Migration
def change
create_table :calendars do |t|
t.string :name
t.timestamps null: false
end
end
end
class CreatePosts < ActiveRecord::Migration
def change
create_table :posts do |t|
t.references :calendar, index: true, foreign_key: true
t.date :date
t.time :time
t.string :focus
t.string :format
t.string :blog_title
t.text :long_copy
t.text :short_copy
t.string :link
t.string :hashtag
t.string :media
t.float :promotion
t.string :target
t.integer :approval
t.text :comment
t.timestamps null: false
end
end
end
所以基本上,一个 user
可以有很多 calendar
而一个 calendar
可以有很多 user
.
当 @user
创建一个新的 @calendar
时,我们会生成一个新的 @administration
:目前正在运行。
我们现在想做的是允许 @user
邀请其他 @user
(无论是否已注册)加入现有的 @calendar
。
这将在受邀 @user
和现有 @calendar
之间创建一个新的 @administration
。
这里棘手的部分——或者至少对我们来说是模糊的部分——似乎是处理注册用户和未注册用户:
对于未注册用户:当"inviting"user
与"invited"user
共享一个calendar
时,我们如何允许后者通过前者输入的电子邮件地址获得邀请,同时允许他通过他选择的电子邮件地址(相同或另一个)注册到应用程序?
对于注册用户:当 "inviting" user
与 "invited" user
共享一个 calendar
时,我们如何允许后者通过前者输入的电子邮件地址获得邀请,同时允许他使用现有帐户登录应用程序(与 "inviting" 使用的电子邮件地址相同或不同的电子邮件地址) user
) 或使用他选择的电子邮件地址注册("inviting" user
使用的电子邮件地址或其他地址)?
最重要的是,我们如何保存与 calendar
(比方说 calendar_id
)相关的信息,以便一旦 "invited" user
登录或已注册,他可以访问 calendar
"inviting" 用户想要授予他访问权限的权限?
注意:我们目前正在使用 Michael Hartl's Rails Tutorial 中建议的自定义 authentication/authorization 系统,而不是使用 Devise
或其他 gem 就此而言。
现在,问题是如何实现:
- 我们是否应该简单地在
Administration
模型中创建一个 invite
方法并在 AdministrationsController#new
中使用它?
- 我们应该创建一个全新的
InvitationsController
吗?
- 我们应该使用像 Devise Invitable* 这样的 gem 吗?
- 或者我们是否缺少一个完全不同、明显的解决方案?
好的,这是我的 2 美分。如果您需要更多信息,请告诉我。
因为您已经进行了自定义身份验证和授权,所以此解决方案可能会对您有所帮助。
我假设您的访问列表应该是这样的,因为我在发布的迁移中看不到您的访问列表。
无论如何,在注册时,您会为每个用户分配一个令牌。
像这样:
before_create :generate_token
private
def generate_token
begin
self.a_token = SecureRandom.hex
end while self.class.exists?(a_token: access_token)
end
然后当用户邀请时简单地分配这个令牌。
现在你需要一个方法在注册时简单地识别令牌,然后填写邀请table。
休息应该很容易。
在您的身份验证模块中只需使用如下方法:
def invited_by
Invite.where(:user_id => current_user.id).first
end
( 我不喜欢 Rails find_by_
你可以使用的方法 find_by_user_id
- 我有点老套;)
(我假设你制作了一个模块,你可以在整个应用程序中使用它)如果没有那么让我知道我会帮助你。
现在您得到了邀请您当前用户的用户。现在只需 return 您为邀请您当前用户的用户分配的权限并继续该应用程序。
希望对您有所帮助。如果您需要更多指导,请告诉我。我对我的会员计划和成为会员的会员权益的申请之一使用了相同的方法。
干杯。
更新
因为您询问了授权模块并且您有自定义身份验证。这里有一些代码。 (部分测试和需要重构请使用它作为指南,它们是我能想到的一些常见任务)
module AuthorisationRelated
def what_are_current_user_roles
objArray = []
current_user.roles.each do |role|
objArray.push role.name
end
return objArray
end
def does_user_have_this_role?(role_name)
result = false
obj_array = what_are_current_user_roles
obj_array.each do |a_role|
if a_role == role_name
result = true
end
end
result
end
def is_admin?
athu = false
if signed_in?
current_user.roles.each do |role|
if role.name == 'admin'
athu = true
end
end
end
return athu
end
# class_instance MUST be a parent class
# If you need to Authenticate Model then your class_instance has to be @instance
def user_allowed_create_and_edit?(class_model, class_instance)
user_is_allowed = false
if permitted_to? :create, class_model.new and has_user_own_this(class_instance)
user_is_allowed = true
else
user_is_allowed = false
end
# Override everything if user is admin
if is_admin?
user_is_allowed = true
end
return user_is_allowed
end
# relation has to be set to access_list
def has_user_own_this(model)
user_who_owns_this = model.access_list.user_id
if current_user.id == user_who_owns_this
return true
else
return false
end
end
def find_current_user_acls
acl = []
acls = AccessList.joins(:user).where("users.id = ?",current_user.id)
acls.each do |an_acl|
acl.push an_acl.id
end
acl
end
end
更新
根据您对授权的良好来源的评论。
我建议使用 Gems 或至少一个可以处理复杂分配的授权 Gem。
我一直以来的情人之一Declarative Authorization。我在一个具有 6 个不同的组 ACL 和桶负载的网站上使用此 Gem 实现了相同的数据库结构,并且拥有超过 500K 的活跃用户。
看看这个教程:http://railscasts.com/episodes/188-declarative-authorization很好的起点。
因为您没有 Devise 或类似的东西,请确保您手边有 current_user
。您可以在 ApplicationController
中定义它
本教程将告诉您如何制作当前用户(付费教程-值得-相信我!)http://railscasts.com/episodes/250-authentication-from-scratch-revised
在我们的Rails4 app中,有四种模式:
class User < ActiveRecord::Base
has_many :administrations, dependent: :destroy
has_many :calendars, through: :administrations
end
class Administration < ActiveRecord::Base
belongs_to :user
belongs_to :calendar
end
class Calendar < ActiveRecord::Base
has_many :administrations, dependent: :destroy
has_many :users, through: :administrations
has_many :posts, dependent: :destroy
end
class Post < ActiveRecord::Base
belongs_to :calendar
end
以下是相应的迁移:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :first_name
t.string :last_name
t.string :email
t.integer :total_calendar_count
t.integer :owned_calendar_count
t.timestamps null: false
end
end
end
class CreateAdministrations < ActiveRecord::Migration
def change
create_table :administrations do |t|
t.references :user, index: true, foreign_key: true
t.references :calendar, index: true, foreign_key: true
t.string :role
t.timestamps null: false
end
end
end
class CreateCalendars < ActiveRecord::Migration
def change
create_table :calendars do |t|
t.string :name
t.timestamps null: false
end
end
end
class CreatePosts < ActiveRecord::Migration
def change
create_table :posts do |t|
t.references :calendar, index: true, foreign_key: true
t.date :date
t.time :time
t.string :focus
t.string :format
t.string :blog_title
t.text :long_copy
t.text :short_copy
t.string :link
t.string :hashtag
t.string :media
t.float :promotion
t.string :target
t.integer :approval
t.text :comment
t.timestamps null: false
end
end
end
所以基本上,一个 user
可以有很多 calendar
而一个 calendar
可以有很多 user
.
当 @user
创建一个新的 @calendar
时,我们会生成一个新的 @administration
:目前正在运行。
我们现在想做的是允许 @user
邀请其他 @user
(无论是否已注册)加入现有的 @calendar
。
这将在受邀 @user
和现有 @calendar
之间创建一个新的 @administration
。
这里棘手的部分——或者至少对我们来说是模糊的部分——似乎是处理注册用户和未注册用户:
对于未注册用户:当"inviting"
user
与"invited"user
共享一个calendar
时,我们如何允许后者通过前者输入的电子邮件地址获得邀请,同时允许他通过他选择的电子邮件地址(相同或另一个)注册到应用程序?对于注册用户:当 "inviting"
user
与 "invited"user
共享一个calendar
时,我们如何允许后者通过前者输入的电子邮件地址获得邀请,同时允许他使用现有帐户登录应用程序(与 "inviting" 使用的电子邮件地址相同或不同的电子邮件地址)user
) 或使用他选择的电子邮件地址注册("inviting"user
使用的电子邮件地址或其他地址)?
最重要的是,我们如何保存与 calendar
(比方说 calendar_id
)相关的信息,以便一旦 "invited" user
登录或已注册,他可以访问 calendar
"inviting" 用户想要授予他访问权限的权限?
注意:我们目前正在使用 Michael Hartl's Rails Tutorial 中建议的自定义 authentication/authorization 系统,而不是使用 Devise
或其他 gem 就此而言。
现在,问题是如何实现:
- 我们是否应该简单地在
Administration
模型中创建一个invite
方法并在AdministrationsController#new
中使用它? - 我们应该创建一个全新的
InvitationsController
吗? - 我们应该使用像 Devise Invitable* 这样的 gem 吗?
- 或者我们是否缺少一个完全不同、明显的解决方案?
好的,这是我的 2 美分。如果您需要更多信息,请告诉我。
因为您已经进行了自定义身份验证和授权,所以此解决方案可能会对您有所帮助。
我假设您的访问列表应该是这样的,因为我在发布的迁移中看不到您的访问列表。
无论如何,在注册时,您会为每个用户分配一个令牌。
像这样:
before_create :generate_token
private
def generate_token
begin
self.a_token = SecureRandom.hex
end while self.class.exists?(a_token: access_token)
end
然后当用户邀请时简单地分配这个令牌。
现在你需要一个方法在注册时简单地识别令牌,然后填写邀请table。
休息应该很容易。
在您的身份验证模块中只需使用如下方法:
def invited_by
Invite.where(:user_id => current_user.id).first
end
( 我不喜欢 Rails find_by_
你可以使用的方法 find_by_user_id
- 我有点老套;)
(我假设你制作了一个模块,你可以在整个应用程序中使用它)如果没有那么让我知道我会帮助你。
现在您得到了邀请您当前用户的用户。现在只需 return 您为邀请您当前用户的用户分配的权限并继续该应用程序。
希望对您有所帮助。如果您需要更多指导,请告诉我。我对我的会员计划和成为会员的会员权益的申请之一使用了相同的方法。
干杯。
更新
因为您询问了授权模块并且您有自定义身份验证。这里有一些代码。 (部分测试和需要重构请使用它作为指南,它们是我能想到的一些常见任务)
module AuthorisationRelated
def what_are_current_user_roles
objArray = []
current_user.roles.each do |role|
objArray.push role.name
end
return objArray
end
def does_user_have_this_role?(role_name)
result = false
obj_array = what_are_current_user_roles
obj_array.each do |a_role|
if a_role == role_name
result = true
end
end
result
end
def is_admin?
athu = false
if signed_in?
current_user.roles.each do |role|
if role.name == 'admin'
athu = true
end
end
end
return athu
end
# class_instance MUST be a parent class
# If you need to Authenticate Model then your class_instance has to be @instance
def user_allowed_create_and_edit?(class_model, class_instance)
user_is_allowed = false
if permitted_to? :create, class_model.new and has_user_own_this(class_instance)
user_is_allowed = true
else
user_is_allowed = false
end
# Override everything if user is admin
if is_admin?
user_is_allowed = true
end
return user_is_allowed
end
# relation has to be set to access_list
def has_user_own_this(model)
user_who_owns_this = model.access_list.user_id
if current_user.id == user_who_owns_this
return true
else
return false
end
end
def find_current_user_acls
acl = []
acls = AccessList.joins(:user).where("users.id = ?",current_user.id)
acls.each do |an_acl|
acl.push an_acl.id
end
acl
end
end
更新
根据您对授权的良好来源的评论。 我建议使用 Gems 或至少一个可以处理复杂分配的授权 Gem。
我一直以来的情人之一Declarative Authorization。我在一个具有 6 个不同的组 ACL 和桶负载的网站上使用此 Gem 实现了相同的数据库结构,并且拥有超过 500K 的活跃用户。
看看这个教程:http://railscasts.com/episodes/188-declarative-authorization很好的起点。
因为您没有 Devise 或类似的东西,请确保您手边有 current_user
。您可以在 ApplicationController
本教程将告诉您如何制作当前用户(付费教程-值得-相信我!)http://railscasts.com/episodes/250-authentication-from-scratch-revised