在用户注册后创建客户端记录的更好方法是什么(相应的客户端记录)

时间:2017-02-23 16:00:27

标签: devise ruby-on-rails-5

基本上我有用户通过使用设计宝石注册自己的应用程序。 我没有像(电子邮件,密码)这样的标准注册表单,而是总共使用了(名称,contact_nr,电子邮件,密码,密码_确认)字段,的额外2个字段(名称,contact_nr) :name和:contact_nr属性存在于' clients'仅限表格。

Table name: clients

    id         :integer          not null, primary key,
    name       :string(255)
    surname    :string(255)
    contact_nr :string(255)
    user_id    :integer

  class Client < ActiveRecord::Base
    belongs_to :user
  end


class User < ActiveRecord::Base
  has_one :client, dependent: :destroy
  after_create :update_user_client

  def name
   return unless client
   client.name
  end

  def contact_nr
    return unless client
    client.contact_nr
  end

  def update_user_client
    Client.last.update_attributes(user: self)
  end

end

在我的RegistrationsController中,我只有一个方法

class RegistrationsController < Devise::RegistrationsController
   before_action :create_client

   private

   def create_client
     return if params[:user].blank?
    Client
       .new(name: params[:user][:name],
        contact_nr: params[:user][:contact_nr])
       .save(validate: false)
   end
 end

困扰我的是那种编写代码,感觉就像代码味道。 你会如何实现它? 谢谢你们期待你们的答案..

2 个答案:

答案 0 :(得分:1)

如果您现在没有正当理由和/或要求,我可以提供的第一条建议是不要将客户和用户分成两个表。这会让事情变得更容易。

如果您有正当理由,请参阅以下有关如何改善此代码段现有状态的建议:

  • Rails及其周围的所有成熟宝石都依赖于“约定优于配置”,所以你应该检查是否有传统的方法来实现相同的结果。
  • 在您的RegistrationsController中,而不是进行params[:user].blank?检查,您应该使用Devise的方式执行此操作,并在before_action回调中提供继承的方法devise_parameter_sanitizer.permit
  • 不是在控制器中创建客户端,而是将其移至模型逻辑,而在用户模型中放置accepts_nested_attributes_for :client
  • 由于您的两个模型(客户端和用户)共享相同的名称,因此请设置before_save回调,以便您可以将用户的名称属性传递给客户端。
  • after_create回调非常危险,因为它不是原子保存(不保证客户端在更新用户记录后会更新)。所以不要使用它。 accepts_nested_attributes_for将处理创建和更新通话。
  • 如果仅通过客户端获取用户的name属性,则无需在用户中保留名称。
  • 如果您想直接从用户模型访问客户的contact_nrname属性,请在其中使用delegate方法。

总而言之,我会重构那段代码:

class User < ActiveRecord::Base
  has_one :client, dependent: :destroy
  accept_nested_attributes_for :client

  delegate :name,       to: :client
  delegate :contact_nr, to: :client

  # optional. if you want to keep name attr in both models.
  before_save :sync_names

  private

  def sync_names
   self.client.name = name if client.present?
  end
end

class RegistrationsController < Devise::RegistrationsController
  before_action :configure_permitted_parameters

  protected

  def configure_permitted_parameters
    added_attrs = [:name, :email, :password, :password_confirmation, client_attributes: [:contact_nr]]

    devise_parameter_sanitizer.permit :sign_up, keys: added_attrs
    devise_parameter_sanitizer.permit :account_update, keys: added_attrs
  end
end

不要忘记更新您的注册和帐户更新表单以接受客户端资源的嵌套属性。

答案 1 :(得分:0)

如果您使用JS验证数据并使用 params.require(:client).permit 进行过滤,则代码看起来很好。尝试在Rspec中创建许多不同的场景。测试通常会发现意外的缺陷。