Rails 设计多态 - 使用 Ajax 获取部分渲染
Posted
技术标签:
【中文标题】Rails 设计多态 - 使用 Ajax 获取部分渲染【英文标题】:Rails Devise Polymorphic - Get Render Partial Using 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:我不知道你是什么意思? 【参考方案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
【讨论】:
以上是关于Rails 设计多态 - 使用 Ajax 获取部分渲染的主要内容,如果未能解决你的问题,请参考以下文章
Rails 4:部分渲染后无法使用javascript(使用ajax)