如何嵌套 devise_invitable 以便用户只能被邀请到 1 家酒店
How to nest devise_invitable such that a user can be invited to only 1 hotel
目标
我想让 user.admin 仅邀请用户入住其中一家 devise_invite
gem 的酒店。
=> User
和 Hotel
通过 Join table UserHotel
.
连接
问题
我开始怀疑我设置devise(_invitable)的方式。按照我目前的设置方式,我无法创建 user_hotel Join_table and/or 将特定酒店参数添加到受邀用户,请参阅下面的输出以进行检查:
控制器
>> @user.hotels => #<ActiveRecord::Associations::CollectionProxy []>
控制台:
pry(main)> User.invitation_not_accepted.last.hotels
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."invitation_token" IS NOT NULL AND "users"."invitation_accepted_at" IS NULL ORDER BY "users"."id" DESC LIMIT [["LIMIT", 1]]
Hotel Load (0.4ms) SELECT "hotels".* FROM "hotels" INNER JOIN "user_hotels" ON "hotels"."id" = "user_hotels"."hotel_id" WHERE "user_hotels"."user_id" = [["user_id", 49]]
=> []
更新
问题似乎出在用户和酒店之间的多对多关系上。当我在 hotel.user.new
之后打破我的控制器 'new' 动作并测试它时,我得到以下结果:
>> @user.hotels => #<ActiveRecord::Associations::CollectionProxy []>
>> @hotel.users => #<ActiveRecord::Associations::CollectionProxy [#<User id: 2, email: "test@hotmail.com", created_at: "2019-11-05 14:17:46", updated_at: "2019-11-05 15:04:22", role: "admin">, #<User id: nil, email: "", created_at: nil, updated_at: nil, role: "admin">]>
备注
我使用设计设置用户,这样我的用户控制器就构建为:
- users/confirmations_controller.rb
- users/invitations_controller.rb
- users/omniauth_callbacks_controller.rb
- users/password_controller.rb
- users/registrations_controller.rb
- users/sessions_controller.rb
- users/unlocks_controller.rb
代码
路线
Rails.application.routes.draw do
devise_for :users
resources :hotels do
devise_for :users, :controllers => { :invitations => 'users/invitations' }
end
end
型号
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
has_many :user_hotels, dependent: :destroy
has_many :hotels, through: :user_hotels
accepts_nested_attributes_for :user_hotels
enum role: [:owner, :admin, :employee]
after_initialize :set_default_role, :if => :new_record?
def set_default_role
self.role ||= :admin
end
devise :invitable, :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable, :invitable
end
class UserHotel < ApplicationRecord
belongs_to :hotel
belongs_to :user
end
class Hotel < ApplicationRecord
has_many :user_hotels, dependent: :destroy
has_many :users, through: :user_hotels
accepts_nested_attributes_for :users, allow_destroy: true, reject_if: ->(attrs) { attrs['email'].blank? || attrs['role'].blank?}
end
views/hotels/show
<%= link_to "invite new user", new_user_hotel_invitation_path(@hotel)%>
控制器/users/invitations_controller.rb
class Users::InvitationsController < Devise::InvitationsController
def new
@hotel = Hotel.find(params[:hotel_id])
@user = @hotel.users.new
end
def create
@hotel = Hotel.find(params[:hotel_id])
@user = @hotel.users.new(hotel_user_params)
@user.invite!
end
private
def hotel_user_params
params.require(:user).permit(:email, :role,
hotel_users_attributes: [:hotel_id])
end
end
views/invitations/new.html.erb
<h2><%= t "devise.invitations.new.header" %></h2>
<%= simple_form_for(resource, as: resource_name, url: user_hotel_invitation_path(@hotel), html: { method: :post }) do |f| %> <%= f.error_notification %>
<% resource.class.invite_key_fields.each do |field| -%>
<div class="form-inputs">
<%= f.input field %>
</div>
<% end -%>
<%= f.input :role, collection: [:owner, :admin, :employee] %>
<div class="form-actions">
<%= f.button :submit, t("devise.invitations.new.submit_button") %>
</div>
<% end %>
你检查了吗:
invitation_limit:
The number of invitations users can send. The
default value of nil means users can send as many invites as they
want, there is no limit for any user, invitation_limit column is not
used. A setting of 0 means they can't send invitations. A setting n >
0 means they can send n invitations. You can change invitation_limit
column for some users so they can send more or less invitations, even
with global invitation_limit = 0.
此外,查看有关 gem 的更多详细信息以获得更多选项将是非常明智的举动:https://github.com/scambra/devise_invitable
我有一些工作,即使很难我不确定这是否是最好的方法(阅读:我非常怀疑)。
class Users::InvitationsController < Devise::InvitationsController
def new
@hotel = Hotel.find(params[:hotel_id])
@user = @hotel.users.new
@user.hotels << @hotel
end
def create
@hotel = Hotel.find(params[:hotel_id])
@user = @hotel.users.new(hotel_user_params)
@user.hotels << @hotel
@user.invite!
end
目标
我想让 user.admin 仅邀请用户入住其中一家 devise_invite
gem 的酒店。
=> User
和 Hotel
通过 Join table UserHotel
.
问题
我开始怀疑我设置devise(_invitable)的方式。按照我目前的设置方式,我无法创建 user_hotel Join_table and/or 将特定酒店参数添加到受邀用户,请参阅下面的输出以进行检查:
控制器
>> @user.hotels => #<ActiveRecord::Associations::CollectionProxy []>
控制台:
pry(main)> User.invitation_not_accepted.last.hotels
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."invitation_token" IS NOT NULL AND "users"."invitation_accepted_at" IS NULL ORDER BY "users"."id" DESC LIMIT [["LIMIT", 1]]
Hotel Load (0.4ms) SELECT "hotels".* FROM "hotels" INNER JOIN "user_hotels" ON "hotels"."id" = "user_hotels"."hotel_id" WHERE "user_hotels"."user_id" = [["user_id", 49]]
=> []
更新
问题似乎出在用户和酒店之间的多对多关系上。当我在 hotel.user.new
之后打破我的控制器 'new' 动作并测试它时,我得到以下结果:
>> @user.hotels => #<ActiveRecord::Associations::CollectionProxy []>
>> @hotel.users => #<ActiveRecord::Associations::CollectionProxy [#<User id: 2, email: "test@hotmail.com", created_at: "2019-11-05 14:17:46", updated_at: "2019-11-05 15:04:22", role: "admin">, #<User id: nil, email: "", created_at: nil, updated_at: nil, role: "admin">]>
备注 我使用设计设置用户,这样我的用户控制器就构建为:
- users/confirmations_controller.rb
- users/invitations_controller.rb
- users/omniauth_callbacks_controller.rb
- users/password_controller.rb
- users/registrations_controller.rb
- users/sessions_controller.rb
- users/unlocks_controller.rb
代码
路线
Rails.application.routes.draw do
devise_for :users
resources :hotels do
devise_for :users, :controllers => { :invitations => 'users/invitations' }
end
end
型号
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
has_many :user_hotels, dependent: :destroy
has_many :hotels, through: :user_hotels
accepts_nested_attributes_for :user_hotels
enum role: [:owner, :admin, :employee]
after_initialize :set_default_role, :if => :new_record?
def set_default_role
self.role ||= :admin
end
devise :invitable, :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable, :invitable
end
class UserHotel < ApplicationRecord
belongs_to :hotel
belongs_to :user
end
class Hotel < ApplicationRecord
has_many :user_hotels, dependent: :destroy
has_many :users, through: :user_hotels
accepts_nested_attributes_for :users, allow_destroy: true, reject_if: ->(attrs) { attrs['email'].blank? || attrs['role'].blank?}
end
views/hotels/show
<%= link_to "invite new user", new_user_hotel_invitation_path(@hotel)%>
控制器/users/invitations_controller.rb
class Users::InvitationsController < Devise::InvitationsController
def new
@hotel = Hotel.find(params[:hotel_id])
@user = @hotel.users.new
end
def create
@hotel = Hotel.find(params[:hotel_id])
@user = @hotel.users.new(hotel_user_params)
@user.invite!
end
private
def hotel_user_params
params.require(:user).permit(:email, :role,
hotel_users_attributes: [:hotel_id])
end
end
views/invitations/new.html.erb
<h2><%= t "devise.invitations.new.header" %></h2>
<%= simple_form_for(resource, as: resource_name, url: user_hotel_invitation_path(@hotel), html: { method: :post }) do |f| %> <%= f.error_notification %>
<% resource.class.invite_key_fields.each do |field| -%>
<div class="form-inputs">
<%= f.input field %>
</div>
<% end -%>
<%= f.input :role, collection: [:owner, :admin, :employee] %>
<div class="form-actions">
<%= f.button :submit, t("devise.invitations.new.submit_button") %>
</div>
<% end %>
你检查了吗:
invitation_limit:
The number of invitations users can send. The default value of nil means users can send as many invites as they want, there is no limit for any user, invitation_limit column is not used. A setting of 0 means they can't send invitations. A setting n > 0 means they can send n invitations. You can change invitation_limit column for some users so they can send more or less invitations, even with global invitation_limit = 0.
此外,查看有关 gem 的更多详细信息以获得更多选项将是非常明智的举动:https://github.com/scambra/devise_invitable
我有一些工作,即使很难我不确定这是否是最好的方法(阅读:我非常怀疑)。
class Users::InvitationsController < Devise::InvitationsController
def new
@hotel = Hotel.find(params[:hotel_id])
@user = @hotel.users.new
@user.hotels << @hotel
end
def create
@hotel = Hotel.find(params[:hotel_id])
@user = @hotel.users.new(hotel_user_params)
@user.hotels << @hotel
@user.invite!
end