Rails - Devise - 将配置文件信息添加到单独的表中

jde*_*sen 2 ruby ruby-on-rails devise

我正在使用 Devise 在我的应用程序中构建注册/身份验证系统。

查看了相当多的用于向设计模型添加信息的资源(例如用户名、传记、头像 URL 等)[资源包括Jaco Pretorius 的网站、这个(格式错误的)SO 问题和这个 SO 问题。

一切都很好——它有效。但我的问题是它保存到 User 模型,根据数据库规范化(也引用这个 SO 问题has_one),它实际上应该保存到通过and连接的 User 子模型belongs_to。

到目前为止,我已经User通过 Devise 创建了一个模型。我还UserProfile通过rails generate脚本创建了一个模型。

user.rb(供参考)

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable, :confirmable, :recoverable, :rememberable, :trackable, :validatable

  has_one :user_profile, dependent: :destroy
end
Run Code Online (Sandbox Code Playgroud)

用户配置文件.rb

class UserProfile < ActiveRecord::Base
  belongs_to :user
end
Run Code Online (Sandbox Code Playgroud)

时间戳_创建_用户_配置文件.rb

class CreateUserProfiles < ActiveRecord::Migration
  def change
    create_table :user_profiles do |t|
      t.string :username, null: false
      t.string :biography, default: ""

      t.references :user, index: true, foreign_key: true

      t.timestamps null: false
    end
    add_index :user_profiles, [:user_id, :username]
  end
end
Run Code Online (Sandbox Code Playgroud)

现在我的问题是,如何收集这两种型号的信息,并通过设备注册表确保所有信息都到达正确的位置?

我已经看到了有关创建状态机的资源(AASM,以及此问题的答案)。我还看到了有关使用 WICKED 创建向导的信息,以及关于同一主题的文章。

对于我的用例来说,这些似乎都太复杂了。有没有某种方法可以简单地将输入与设备分开并确保最终位于正确的位置?

jde*_*sen 5

我认为,我不会简单地评论导致我得出最终答案的答案,而是将答案存档在这里,以防将来有人也尝试找到这个答案:

我假设您已经进行了某种设置,就像我上面所做的那样。

第一步是您需要将用户控制器修改为accept_nested_attributes_for配置文件引用,并向模型添加实用程序方法,以便在代码中请求时,应用程序可以检索构建的配置文件模型或构建一个。

用户模型最终看起来像这样:

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable, :confirmable, :recoverable, :rememberable, :trackable, :validatable

  has_one :user_profile, dependent: :destroy
  accepts_nested_attributes_for :user_profile

  def user_profile
    super || build_user_profile
  end
end
Run Code Online (Sandbox Code Playgroud)

其次,您需要修改您的注册/帐户更新表单,以便能够将此辅助模型的属性传递到控制器中,并最终能够为父模型构建配置文件。

您可以通过使用来做到这一点f.fields_for。

将这样的内容添加到您的表单中:

<%= f.fields_for :user_profile do |user_profile_form| %>
 <%= user_profile_form.text_field :attribute %>
<% end %>
Run Code Online (Sandbox Code Playgroud)

我的具体案例中的一个例子是:

<%= f.fields_for :user_profile do |user_profile_form| %>
  <div class="form-group">
    <%= user_profile_form.text_field :username, class: "form-control", placeholder: "Username" %>
  </div>
<% end %>
Run Code Online (Sandbox Code Playgroud)

最后,您需要告诉 Devise 它应该接受这个新的参数哈希并将其传递给模型。

如果您创建了自己的 RegistrationsController 并扩展了 Devise,它应该类似于以下内容:

class RegistrationsController < Devise::RegistrationsController
  private
    def sign_up_params
      params.require(:user).permit(:email, :password, user_profile_attributes: :username)
    end
end
Run Code Online (Sandbox Code Playgroud)

(当然,请根据您的特定用例进行适当的更改。)

如果您只是将 Devise 清理方法添加到应用程序控制器中,则它应该类似于以下内容:

class ApplicationController < ActionController::Base
  before_filter :configure_permitted_parameters, if: :devise_controller?

  protected
    def configure_permitted_parameters
      devise_parameter_sanitizer.for(:sign_up) {|u|
        u.permit(:email, :password, user_profile_attributes: :username)}
    end
end
Run Code Online (Sandbox Code Playgroud)

(再次,针对您的特定用例进行适当的更改。)

一个小注释user_profile_attributes: :username:当然,请注意这是一个哈希值。如果您要传递多个属性,例如作为account_update(提示提示),则需要像这样传递它们user_profile_attributes: [:attribute_1, :attribute_2, :attribute_3]。