如何在不通过表单传递数据的情况下更新嵌套资源 [英] How do I update a nested resource without passing the data via a form
问题描述
模型
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屋!