Rails 4 app:如何允许用户邀请其他用户在特定模型实例上进行协作?

时间:2015-07-09 22:58:01

标签: ruby-on-rails authentication ruby-on-rails-4 model-view-controller authorization

在我们的Rails 4应用程序中,有四种模式:

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可以包含多个calendarcalendar可以包含多个user

@user创建新的@calendar时,我们会生成新的@administration:目前正在使用此功能。

我们现在要做的是允许@user邀请已注册或未注册的其他@user加入现有@calendar

这会在受邀@administration和现有@user之间创建新的@calendar

这里棘手的部分 - 或者至少是我们的模糊部分 - 似乎是处理已注册和未注册的用户:

  • 对于未注册的用户:当“邀请”user与“邀请”calendar共享user时,我们如何允许后者通过电子邮件地址由前者输入,同时允许他通过他选择的电子邮件地址(相同或另一个)注册到应用程序?

  • 对于注册用户:当“邀请”user与“邀请”calendar共享user时,我们如何允许后者通过电子邮件地址由前者输入,同时允许他使用现有帐户登录应用程序(与“邀请”user使用的电子邮件地址相同或不同的电子邮件地址)或注册他选择的电子邮件地址(“邀请”user或其他地址使用的电子邮件地址)?

最重要的是,我们如何保留与calendar相关的信息(比方说calendar_id),以便“受邀”user登录或注册后,他有权访问calendar“邀请”用户想要授予他访问权限吗?

注意:我们目前正在使用Michael Hartl's Rails Tutorial中建议的自定义身份验证/授权系统,并且未使用Devise或其他gem。

现在,问题是如何实现这一目标:

  • 我们是否应该在invite模型中创建Administration方法并在AdministrationsController#new中使用它?
  • 我们应该创建一个全新的InvitationsController吗?
  • 我们应该使用像Devise Invitable *?
  • 这样的宝石吗?
  • 或者我们缺少一个完全不同的,明显的解决方案吗?

1 个答案:

答案 0 :(得分:1)

好的,这是我的2美分。如果您需要更多信息,请与我们联系。

因为您已经进行了自定义身份验证和授权,所以此解决方案可能会对您有所帮助。

enter image description here

我认为您的访问列表应该是这样的,因为我在发布的迁移中看不到您的访问列表。

无论如何,在注册时,您需要为每个用户分配一个令牌。

这样的事情:

before_create :generate_token

private
  def generate_token
    begin
      self.a_token = SecureRandom.hex
    end while self.class.exists?(a_token: access_token)
  end

然后,当用户邀请时,只需分配此令牌即可。

现在,您需要在注册时使用方法来识别令牌,然后填写Invite表。

休息应该很容易。

在身份验证模块中,只需使用以下方法:

 def invited_by
   Invite.where(:user_id => current_user.id).first
 end

(我不喜欢你可以使用的find_by_方法find_by_user_id - 我有点老式;)

(我假设您制作了一个模块,您可以在整个应用程序中使用它)如果没有,请告诉我,我会帮助您完成配对。

所以现在你有了邀请你当前用户的用户。现在,只需返回您为当前用户邀请的用户分配的权限,然后继续使用该应用程序。

希望它有所帮助。如果您需要更多指导,请告诉我。我使用相同的方法进行联盟计划申请和成为联盟会员的会员福利。

干杯。

<强>更新

因为您询问了授权模块并且您有自定义身份验证。这里有一些代码。 (部分测试和需要重构请使用它作为指导,它们是我能想到的一些常见任务)

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或至少一个可以处理复杂任务的Authorization 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