【问题标题】:Rails AJAX request to controller method that then calls javascript functionRails AJAX 请求控制器方法,然后调用 javascript 函数
【发布时间】:2018-10-22 09:08:34
【问题描述】:

我查看了数十篇堆栈溢出帖子,但没有找到可行的解决方案,这就是为什么我要寻求一个其他有据可查的用例。

我有一个按钮可以执行此操作。

  • 点击后,调用自定义控制器方法来更新模型并执行其他操作
  • 调用一个javascript函数来更新页面而不重新加载它(ajax)

现在,我能够调用自定义控制器方法的唯一方法是通过这种感觉非常hacky的方式。我已将其简化为尽可能简单。

routes.rb

match 'admin/:id/toggleAdmin' => 'admin#toggleAdmin', via: [:patch, :put], as: :toggleAdmin

list.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 请求。 (我期待一个布尔值变化和闪光)。以下是相关代码:

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

edit.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

【问题讨论】:

    标签: javascript jquery ruby-on-rails ruby ajax


    【解决方案1】:

    路由

    首先,如果您需要在资源中嵌套自定义路由,您可以将其定义为该资源的成员:

    resources :users do
      put 'toggle_admin', on: :member
    end
    

    返回:

    toggle_admin    PUT    /users/:id/toggle(.:format)    users#toggle
    

    其次,你的方法名应该是snake_case:def toggle_admin
    See "Instance Methods" section

    控制器

    如果您只是想将用户更新为管理员(在这里通过此方法猜测: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 更新视图而不重新加载时,您需要使用 partial。正是这个部分将在特定 DOM 元素上的 .js.erb 文件中刷新。

    让我们为 user#edit 视图做一个例子。
    首先,您需要在部分 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 } %>")
    

    瞧!单击链接时,您会使用来自控制器的新信息刷新编辑视图,而无需重新加载视图。

    当然,这是经典资源编辑视图的示例,但您可以根据任何情况对其进行调整。只需在路由、控制器、控制器方法和视图(AdminController、列表视图等)之间保持良好的命名


    编辑

    要处理 flash 消息,您需要在布局中添加 > application.html.erb :

      <body>
        <% flash.each do |key, value| %>
          <%= content_tag :div, value, class: "classname" %>
        <% end %>
        <%= yield %>
      </body>
    

    【讨论】:

    • 非常感谢您的详细回复。但是,我无法让它在一个新项目上工作。我继续在控制器部分收到语法错误。 /home/frillybob/demo/app/controllers/users_controller.rb:8: syntax error, unexpected ':', expecting '}' format.js { info: "The user with an ID of #{idT ^ /home/frillybob/demo/app/controllers/users_controller.rb:8: syntax error, unexpected '}', expecting keyword_end ir admin attribute toggled!" } ^ /home/frillybob/demo/app/controllers/users_controller.rb:86: syntax error, unexpected keyword_end, expecting end-of-input
    • 从头开始时出现上述错误。在第 8 行注释掉 info: 部分时,我在控制器 Couldn't find User with id=edit 中收到错误消息。在线搜索让我回到我的主应用程序中进行设计。然而,这是一个失败的原因,因为我不知道如何修复那里的无数错误。
    • @frillybob 对于第一个错误,我在我的答案中修复了它。对于Couldn't find User with id=edit 错误,它只是关于参数。它来自这里的用户:toggle_admin_user_path(user)。视图的网址是什么?当您单击链接时,您的日志中有哪些参数?您可以使用视图代码编辑您的问题以查看您发送给控制器的参数吗?
    • 感谢您的回复。当我使用 /users/1/edit 时,我可以单击 toggle_admin 并执行该方法。这对我来说是一个简单的错误。但是,我不会在不重新加载的情况下重新渲染页面。在控制台中,我收到一个错误 No template found for UsersController#toggle_admin, rendering head :no_content 我也没有收到任何 Flash 消息。我将使用更多信息更新原始帖子。感谢您的帮助!
    • 为了处理我对我的帖子进行编辑的 Flash 消息。对于刷新切换,我制作了一个演示应用程序,但无法重现您的错误。每次单击“切换”时,我的编辑部分刷新而不将&lt;%= user.admin %&gt; 重新加载为真/假
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-28
    • 2013-06-24
    • 2013-12-09
    • 2015-06-02
    • 1970-01-01
    • 2019-09-05
    相关资源
    最近更新 更多