我查看了数十个堆栈溢出帖子,但没有找到有效的解决方案,这就是为什么我要寻求一个有据可查的用例。
我有一个按钮应该这样做。
- 单击时,调用更新模型并执行其他操作的自定义控制器方法
- 调用 javascript 函数来更新页面而不重新加载它 (ajax(
现在,我能够调用自定义控制器方法的唯一方法是通过这种感觉非常黑客的方式。我已经把它简化为尽可能简单。
路线.rb
match 'admin/:id/toggleAdmin' => 'admin#toggleAdmin', via: [:patch, :put], as: :toggleAdmin
列表.html.erb
<td><%= link_to "Toggle Admin", toggleAdmin_path(id: user.id), method: :patch %></td>
admin_controller.rb
class AdminController < ApplicationController
def toggleAdmin
idToToggle = User.find(params[:id]).id
if idToToggle == current_user.id
redirect_to admin_list_path, danger: "You tried to make yourself a normal user! Don't do that!"
else
User.find(params[:id]).updateToAdmin()
redirect_to admin_list_path, info: "The user with an ID of #{idToToggle} has had their admin attribute toggled!"
end
end
结束
我想做的不是在切换管理员时重新加载页面,而是使用一些 javascript 重写 dom 的那部分。
有什么更好的方法呢?
以下是我已经尝试过的各种资源中的一些。
- 如何从视图中调用控制器的方法?
- 我们可以从视图中调用控制器的方法吗(理想情况下,我们从帮助程序调用(?
- 使用 rails-Ajax 调用控制器方法?
- https://www.reddit.com/r/rails/comments/7iyp6g/want_a_button_to_call_a_method_apparently_this_is/
- 如何从 html.erb 调用 JavaScript 函数
感谢您的帮助。
---编辑以获取更多信息。
使用 clean rails 应用程序,我现在能够更干净地调用控制器方法,但我没有收到更新页面以显示操作已完成的 ajax 请求。(我期待布尔值的变化和闪光(。以下是以下相关代码:
用户.js
$("#edit-form").html("<%= j render partial: 'form', locals: { user: @user } %>")
_form.html.erb
<%= form_for user do |form| %>
<%= user.admin %>
<% end %>
<%= link_to "Toggle Admin", toggle_admin_user_path(user), method: :put, remote: true %>
编辑.html.erb
<h1>Editing User</h1>
<div id="edit-form">
<%= render partial: 'form', locals: { user: @user } %>
</div>
<%= link_to 'Show', @user %> |
<%= link_to 'Back', users_path %>
users_controller.rb 请注意,我只包括了toggle_admin
和其他几种方法,因为其余的只是脚手架。
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy, :toggle_admin]
def toggle_admin
if 1 == 1
logger.info "This is from info"
u = User.find(params[:id])
u.admin = !(u.admin)
u.save
respond_to do |format|
format.js { flash[:info] = "The user with an ID of #{@user.id} has had their admin attribute toggled!" }
end
else
redirect_to admin_list_path, danger: "You tried to make yourself a normal user! Don't do that!"
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
@user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.fetch(:user, {})
end
end
路由
首先,如果您需要资源中的嵌套自定义路由,则可以将其定义为此资源的成员:
resources :users do
put 'toggle_admin', on: :member
end
返回:
toggle_admin PUT /users/:id/toggle(.:format) users#toggle
其次,您的方法名称应为snake_case:def toggle_admin
请参阅"实例方法"部分
控制器
如果您只想将用户更新为管理员(通过此方法猜测此处:User.find(params[:id]).updateToAdmin()
(,则可以在UsersController
中定义自定义toggle_admin
方法。
你触发 ajax 请求的自定义方法应该响应 js 格式并指向对应的 js 视图(toggle_admin.js.erb
(作为资源User
的成员,可以将其添加到before_action
回调中,以便在调用该方法时返回正确的用户。
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy, :toggle_admin]
#...
def toggle_admin
if #some condition
# do some logic here
respond_to do |format|
format.js { flash[:info] = "The user with an ID of #{@user.id} has had their admin attribute toggled!" }
end
else
redirect_to admin_list_path, danger: "You tried to make yourself a normal user! Don't do that!"
end
end
end
视图
在 rails 视图中,当您想使用 ajax 更新视图而不重新加载时,需要使用部分视图。正是这个部分将在特定 DOM 元素上的.js.erb
文件中刷新。
让我们为用户#编辑视图做一个例子。
例如,首先,您需要在部分form
中呈现视图,并将其包装到具有特定id
div 中 :
edit.html.erb
<div id="edit-form">
<%= render partial: 'form', locals: { user: @user } %>
</div>
部分:
_form.html.erb
<%= form_for user do |form| %>
# the form
<% end %>
<%= link_to "Toggle Admin", toggle_admin_user_path(user), method: :put, remote: true %>
# don't forget the remote: true for the ajax call
最后是自定义操作的.js.erb
(假设你有jquery(:
toggle_admin.js.erb
$("#edit-form").html("<%= j render partial: 'form', locals: { user: @user } %>")
瞧! 单击该链接时,您可以使用控制器中的新信息刷新编辑视图,而无需重新加载视图。
当然,这是经典资源的编辑视图的示例,但您可以针对任何情况对其进行调整。只需在路由,控制器,控制器方法和视图(管理控制器,列表视图等(之间保持良好的命名即可
编辑
要处理 flash 消息,您需要在布局>应用程序中添加.html.erb :
<body>
<% flash.each do |key, value| %>
<%= content_tag :div, value, class: "classname" %>
<% end %>
<%= yield %>
</body>