如何在不通过表单传递数据的情况下更新嵌套资源

楷模

class User  :destroy, :inverse_of => :user has_many :companies, :through => :roles accepts_nested_attributes_for :roles, :limit => 1, :allow_destroy => true end class Role  :roles belongs_to :company, :inverse_of => :roles accepts_nested_attributes_for :company end class Company  :destroy, :inverse_of => :user has_many :users, :through => :roles validates :name, presence: true end 

自定义设计注册控制器

 class RegistrationsController < Devise::RegistrationsController # GET /resource/sign_up def new build_resource({}) @role = resource.roles.build(role: "owner", active: 1, default_role: 1) @company = @role.build_company set_minimum_password_length yield resource if block_given? respond_with self.resource end protected def sign_up_params params.require(:user).permit(:email, :password, :password_confirmation, roles_attributes: [ company_attributes: [ :id, :name ] ] ) end end 

HTML

  {:class => "form-signin" }, as: resource_name, url: registration_path(resource_name)) do |f| %>   

Register

这有效 – 我的中间角色是使用id_user和id_company创建的。 问题是我想在新创建的角色中设置一些其他字段。 例如,我有一个:我想设置为“所有者”的角色列,因为这是一个全新的公司,注册的用户是所有者。

我想在控制器中执行此操作以防止用户提交的表单中的任何批量分配问题。

我是否需要在自定义设计注册控制器中以某种方式设置它并创建完整的自定义创建操作?

我承认我可能不会解释这一点,因为我在整个嵌套表格和活动记录等方面都是一个新手。

UPDATE

它不漂亮,但我只是粘贴在我的新控制器的末尾:

  def set_minimum_password_length if devise_mapping.validatable? @minimum_password_length = resource_class.password_length.min end end 

更新2

我复制了主代码与当前版本代码。 一旦我解决了这一切都很好。

我会覆盖创建操作,以便您可以对角色属性进行硬编码(并且用户不会乱用)。

您在新操作中分配它们,但是您需要隐藏字段,以便它们被传递以创建并持久存储到数据库中。 但是,这不是一个好主意,因为任何人都可以编辑HTML并更改这些值。 最好在create action中执行此操作,如下所示:

 class RegistrationsController < Devise::RegistrationsController def create build_resource(sign_up_params) # The last role should be the one created in the form # We set the values here so they get saved and they aren't passed in the form resource.roles.last.assign_attributes(role: "owner", active: 1, default_role: 1) resource.save yield resource if block_given? if resource.persisted? if resource.active_for_authentication? set_flash_message :notice, :signed_up if is_flashing_format? sign_up(resource_name, resource) respond_with resource, location: after_sign_up_path_for(resource) else set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_flashing_format? expire_data_after_sign_in! respond_with resource, location: after_inactive_sign_up_path_for(resource) end else clean_up_passwords resource set_minimum_password_length respond_with resource end end end