【问题标题】:Rails Devise Polymorphic - Get Render Partial Using AjaxRails 设计多态 - 使用 Ajax 获取部分渲染
【发布时间】:2013-10-27 02:49:50
【问题描述】:

我已经使用来自this answer 的多个模型实现了设计注册。这个 tuts 从路径中获取参数 user_type。 我想用选择user_type 来改变它。因此,当我在 select_tag 上选择一个值时,将获得一个参数 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

<h2>Add User</h2>

<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
  <%= devise_error_messages! %>

  <div><%= f.label :username, "Username" %><br />
  <%= f.text_field :username %></div>

  <div><%= f.label :email, "Email" %><br />
  <%= f.email_field :email %></div>

  <div><%= f.label :password, "Password" %><br />

  <%= f.password_field :password %></div>

  <div><%= f.label :password_confirmation, "Password Confirmation" %><br />
  <%= f.password_field :password_confirmation %></div>

  <div><%= f.label :usertype, "Select User Type" %><br />
  <%= f.select(:usertype, options_for_select([['-- User Type --', nil], ['Admin', 'admin'], ['Player', 'player']], selected: '-- User Type --' )) %>
   </div> 

   <div id="selectuser">
   </div>
  <% end %>

  <div><%= f.submit "Submit" %></div>
<% end %>

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

selectuser.js.erb

<%  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


   nesteds = fields_for child_class_name.constantize.new do |rf|
     render :partial => child_class_name.underscore + '_fields', :locals => {:f => rf}
   end
%>
$("#selectuser").append("<%= j nesteds %>");

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

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

【问题讨论】:

  • 如果性别都是男是女,就不用碰服务器,直接在模板里写代码就行了。
  • @BillyChan:我不知道你是什么意思?

标签: ruby-on-rails ajax ruby-on-rails-3.2 devise


【解决方案1】:

你在这里混淆了几件事。

  • 您的路线定义了一个默认值

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

 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" %><br />
<%= select_tag(:usertype, options_for_select([['-- User Type --', nil], ['Admin', 'admin'], ['Player', 'player']], selected: '-- User Type --' )) %>

【讨论】:

  • 感谢 phoet,我已经尝试过了,但没有任何变化,仍然无法正常工作。
  • 我在用户模型上有属性 usertype
【解决方案2】:

我认为你有很多问题,但最大的问题在这里:

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 函数将变量发送到部分。

我不喜欢你试图动态生成“f.fields_for”的想法——它应该已经设置好了,你只更改该块内的字段。这是一个被称为DRY (don't repeat yourself) 编程的原则。如果你愿意,我可以为你写我喜欢的版本,而不是尝试monkeypatch这个?

【讨论】:

  • 感谢rich peck,我看到你的代码会出错,看到nesteds = fields_for child_class_name.constantize.new do |rf| wirhout end ?
  • 嗯,我没看到!老实说,我会以不同的方式编写代码^_^
  • 但是当你尝试你的代码时,得到了像syntax error, unexpected $end, expecting keyword_end这样的错误。如果nesteds 不使用,则nesteds 将用于什么变量。
  • 感谢 rick peck,但在您回答之前,我已经尝试过了。修复错误但仍然无法正常工作。
  • 嗯好吧,让我看看有什么办法可以解决
【解决方案3】:

在你的控制器文件中返回

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

当控制器返回 json 给你的 ajax 函数时,注入以下内容 -

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

【讨论】:

    【解决方案4】:

    当你试图渲染你的部分时,你必须添加一个 =:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-30
      • 2013-01-29
      相关资源
      最近更新 更多