Rails设计多态 – 使用Ajax渲染部分渲染

我已经从这个答案实现了多个模型的设计注册。 这个tuts从路径获取params user_type 。 我想用select user_type更改它。 因此,当我在select_tag上选择一个值时,将获得一个param user_type。

我有一些代码看起来像:

的routes.rb

  namespace :cp do devise_scope :user do match '/add_user' => 'registrations#new' match '/select/admin' => 'registrations#selectuser', :user => { :usertype => 'admin' } match '/select/player' => 'registrations#selectuser', :user => { :usertype => 'player' } end end 

registrations_controller.rb

  def selectuser respond_to do |format| format.js end end 

new.html.erb

 

Add User

resource_name, :url => registration_path(resource_name)) do |f| %>





$("#user_usertype").on('change', function() { var s = $(this).val(); $.ajax({ type: 'GET', url: 'http://localhost:3000/cp/select/' + s, dataType: "HTML" }); });

selectuser.js.erb

  child_class_name.underscore + '_fields', :locals => {:f => rf} end %> $("#selectuser").append(""); 

当我选择管理员值时,记录:

 Started GET "/cp/select/admin" for 127.0.0.1 at 2013-10-21 17:00:04 +0700 Processing by Cp::RegistrationsController#selectuser as HTML Parameters: {"user"=>{"usertype"=>"admin"}} Rendered cp/registrations/_admin_fields.html.erb (4.0ms) Rendered cp/registrations/selectuser.js.erb (7.0ms) Completed 200 OK in 22ms (Views: 22.0ms | ActiveRecord: 0.0ms) 

_admin_fields.html.erb没有出现在#selectuser

你在这里混淆了几件事。

  • 您的路线定义默认值

如果您需要从下拉列表中进行选择,则无需在此处定义默认值。 它只会让事情复杂化

  match '/add_user' => 'registrations#new', :user => { :usertype => nil } match '/select/admin' => 'registrations#selectuser', :user => { :usertype => 'admin' } match '/select/player' => 'registrations#selectuser', :user => { :usertype => 'player' } 
  • 你没有使用正确的表格助手

如果你想获得params[:user][:usertype]的输出,你需要使用f.select 。 如果您的模型没有这样的属性,您可以将它作为attr_accessor添加到您的模型中。

 <%= label :usertype, "Select User Type" %>
<%= select_tag(:usertype, options_for_select([['-- User Type --', nil], ['Admin', 'admin'], ['Player', 'player']], selected: '-- User Type --' )) %>

我认为你有很多问题,但最重要的是:

 nesteds = fields_for child_class_name.constantize.new do |rf| render :partial => child_class_name.underscore + '_fields', :locals => {:f => rf} 

您正尝试在变量中呈现“ fields_for ”帮助器。 问题是这个变量被视为一个字符串,这意味着它不再是一个帮助器,并且不会导致出现fields_for元素。 这是因为我们不知道你的系统的哪个部分不起作用 –

你的Ajax被解雇了吗? 您的路线是否正确发送请求?


就个人而言,我会重新考虑你的系统的这部分是如何工作的

我将从渲染的selectuser.js.erb中删除逻辑,并将其放入控制器,如下所示:

  def selectuser params[:user][:usertype] ||= 'admin' if ["admin", "player"].include? params[:user][:usertype].downcase child_class_name = params[:user][:usertype].downcase.camelize usertype = params[:user][:usertype].downcase else child_class_name = "Admin" usertype = "admin" end respond_to do |format| format.js { @render = child_class_name.underscore + '_fields', @rf = rf} end end 

然后在你的JS中,你可以让JS做它诞生的东西:

 $("#selectuser").html("<%=j render :partial => @render, locals: {:f = @rf} %>"); 

这意味着在您的child_class_name_fields.html.erb中,您需要具有以下内容:

 <%= f.fields_for child_class_name.constantize.new do |rf| %> <%= rf.text_field :name %> <% end %> 

更新

我现在正在努力解决这个问题,因为我会完全不同地做到这一点。 我会将整个逻辑移动到控制器中,并且只通过:render函数将变量发送到partial。

我不喜欢你想要动态生成“f.fields_for”的想法 – 它应该已经设置,你只需要更改该块内的字段。 这是一个被称为DRY(不要重复自己)编程的原则。 如果你愿意,我可以为你编写我喜欢的版本,而不是尝试monkeypatch这个?

在您的控制器文件中返回

 render json: {"fields" => render_to_string(partial: "admin_fields") } 

当控制器返回json到你的ajax函数时注入以下 –

 $('#selectuser').html(fields) 

当您尝试渲染部分时,您必须添加=:

 <%= params[:user][:usertype] ||= 'admin' # ^ This makes whatever is being returned in this block to be added to the output