如何在不通过表单传递数据的情况下更新嵌套资源 [英] How do I update a nested resource without passing the data via a form

查看:129
本文介绍了如何在不通过表单传递数据的情况下更新嵌套资源的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

模型

  class User< ActiveRecord :: Base 
devise:database_authenticatable,:可注册,
:可恢复,可记忆,可追踪,可验证
has_many:roles,:dependent => :destroy,:inverse_of => :user
has_many:companies,:through => :roles
acceptance_nested_attributes_for:roles,:limit => 1,:allow_destroy => true

end

class Role< ActiveRecord :: Base
belongs_to:user,:inverse_of => :roles
belongs_to:company,:inverse_of => :角色
acceptance_nested_attributes_for:company
end

class公司< ActiveRecord :: Base
has_many:roles,:dependent => :destroy,:inverse_of => :user
has_many:users,:through => :角色
验证: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
生成资源如果block_given?
respond_with self.resource
end

protected

def sign_up_params
params.require(:user).permit(:email,密码:password_confirmation,roles_attributes:[company_attributes:[:id,:name]])
end

end

HTML

 <%= form_for资源,:html => {:class =>form-signin},as:resource_name,url:registration_path(resource_name))do | f | %GT; 
<%= render partial:shared / flash%>
<%= devise_error_messages! %GT;
< h1 class =form-signin-heading text-muted> Register< / h1>
<%= f.email_field:email,class:form-control,占位符:Email,autofocus:true%>
<%= f.password_field:password,class:form-control,占位符:密码,自动填充:关闭%>
<%= f.password_field:password_confirmation,class:form-control,占位符:密码确认,自动填充:关闭%>

<%= f.fields_for:roles,resource.roles.build do | r | %GT;
<%= r.fields_for:company,resource.roles.build.build_company do | c | %GT;
<%= c.text_field:name,class:form-control,占位符:Company,autocomplete:off%>
<%end%>
<%end%>

< button class =btn btn-lg btn-primary btn-blocktype =submit>
注册
< / button>
<%end%>

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



我想在控制器中这样做,以防止用户提交表单中的任何质量分配问题。



我需要在自定义设计注册控制器中设置这个,并创建一个完整的自定义创建动作?



我承认我可能不会很好地解释这一点,因为我对整个嵌套表单和活动记录等都是一个新手。 p>

更新



它不漂亮,但我刚刚粘贴在我新的结尾控制器:

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

更新2



我已经复制了主代码和当前的版本代码。一旦我确定这一切都很好。

解决方案

我将覆盖创建操作,以便您可以进行硬编码(用户可以'这个角色属性。



你在新的动作中分配这些属性,但你需要有隐藏的字段,以便被传递来创建和保持进入数据库。但是,这不是一个好主意,因为任何人都可以编辑HTML并更改这些值。最好在创建动作中执行此操作,如下所示:

  class RegistrationsController< Devise :: RegistrationsController 
def create
build_resource(sign_up_params)

#最后一个角色应该是以
#的形式创建的,我们在这里设置值,以便他们得到保存,并且它们不以
resource.roles.last.assign_attributes(role:owner,active:1,default_role:1)的形式传递

resource.save
yield资源如果block_given?
如果resource.persisted?
如果resource.active_for_authentication?
set_flash_message:notice,:signed_up if is_flashing_format?
sign_up(resource_name,resource)
respond_with资源,位置:after_sign_up_path_for(资源)
else
set_flash_message:通知,:signed_up_but _#{resource.inactive_message}if is_flashing_format?
expire_data_after_sign_in!
respond_with资源,位置:after_inactive_sign_up_path_for(资源)
end
else
clean_up_passwords资源
set_minimum_password_length
respond_with资源
end
end
end


Models

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
  has_many :roles, :dependent => :destroy, :inverse_of => :user
  has_many :companies, :through => :roles
  accepts_nested_attributes_for :roles, :limit => 1, :allow_destroy => true

end

class Role < ActiveRecord::Base
  belongs_to :user, :inverse_of => :roles
  belongs_to :company, :inverse_of => :roles
  accepts_nested_attributes_for :company
end

class Company < ActiveRecord::Base
  has_many :roles, :dependent => :destroy, :inverse_of => :user
  has_many :users, :through => :roles
  validates :name, presence: true
end

Custom Devise Registration Controller

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

<%= form_for(resource, :html => {:class => "form-signin" }, as: resource_name, url: registration_path(resource_name)) do |f| %>
    <%= render partial: "shared/flash" %>
    <%= devise_error_messages! %>
    <h1 class="form-signin-heading text-muted">Register</h1>
    <%= f.email_field :email, class: "form-control", placeholder: "Email", autofocus: true %>
    <%= f.password_field :password, class: "form-control", placeholder: "Password", autocomplete: "off" %>
    <%= f.password_field :password_confirmation, class: "form-control", placeholder: "Password Confirmation", autocomplete: "off" %>

    <%= f.fields_for :roles, resource.roles.build do |r| %>
    <%= r.fields_for :company, resource.roles.build.build_company do |c| %>
          <%= c.text_field :name, class: "form-control", placeholder: "Company", autocomplete: "off" %>
    <% end %>
    <% end %>

    <button class="btn btn-lg btn-primary btn-block" type="submit">
        Register
    </button>
<% end %>

This works - my intermediate Role is created with the id_user and id_company. The problem is I want to set the some additional fields in the newly created Role. for example I have a :role column that I want to set to 'owner' as this is the a brand new company and the user that signed up is the owner.

I want to do this in the controller to prevent any mass assignment issues from the user submitted form.

Do I need to set this somehow in the custom devise registration controller and create a full custom create action?

I admit I am likely not explaining this well as I am a bit of a newbie on the whole nested forms and active record etc.

UPDATE

It's not pretty but I just pasted this at the end of my new controller:

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

UPDATE 2

I had copied the master code vs the current version code. Once I fixed that it's all good.

解决方案

I would overwrite the create action so that you can hardcode (and the user can't mess with) the role attributes.

You're assigning them in the new action, but you'd need to have hidden fields so they get passed to create and persist into the database. However, that's not a good idea because anyone can edit the HTML and change those values. It's better to do this in the create action instead like so:

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

这篇关于如何在不通过表单传递数据的情况下更新嵌套资源的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆