【问题标题】:Rails: set a value using a linkRails:使用链接设置值
【发布时间】:2011-07-12 20:20:35
【问题描述】:

我在尝试创建提交编辑表单的链接时需要帮助。

假设我有一个对象列表

Object -   Color -   Own? 
Ball   -   Red   -  false   - [button]
Hat    -   Blue  -  true    - [button]
Shoe   -   Green -  false   - [button]

当我点击 [按钮] 时,我想设置“拥有?”为真。

路线

  resources :toys

控制器

def edit
    @toy = Toy.find(params[:id])
end

def update
  @toy = Toy.find(params[:id])
  if @Toy.update_attributes(params[:toy])
    flash[:notice] = "Toy Updated"
    redirect_to @toy
  else
    render 'edit'
  end
end

查看

<h2>Toys</h2>
    <% if @toys %>
    <% @toys.each do |toy| %>
          <%= toy.name %> - <%= link_to 'Set Own', edit_toy_path(:id=>toy.id, :owned=>'true')%>
    <br/>
    <% end %>
<% else %>
    None
<% end %>

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 forms controllers link-to


    【解决方案1】:

    这就是您如何设置控制器操作的全部内容。我不完全确定我理解你想如何使用你的,但我有一个类似的案例,我会告诉你我认为你应该能够适应你的情况。

    在我的例子中,我有一个菜单按钮,它在会话中设置一个值,以使菜单面板在用户查看的任何视图中保持打开或关闭。

    首先,您需要一个控制器操作来完成您感兴趣的工作。我创建了一个“SharedController”来处理不属于任何特定视图或其他控制器的应用程序范围的事情。

    class SharedController < ApplicationController
    
      # Used by AJAX links to set various settings in shared views
      def edit
        session[:admin_menu] = params[:admin_menu].to_sym if params[:admin_menu]
        session[:advanced_search] = params[:advanced_search].to_sym if params[:advanced_search]
    
        render :nothing => true
      end
    end
    

    此控制器操作可以在会话中设置以下两个值之一:“admin_menu”(布尔值)或“advanced_search”(布尔值)。然后某些视图会询问 admin_menu 或 advanced_search 的会话值是否为真,如果是,它们会显示该视图。

    您可以使用相同的逻辑。比如:

    def edit
      object= Object.find(params[:object_id])
      object.own = params[:own]
      object.save
    end
    

    要使用链接触发此控制器操作,您需要有一个接受 GET 请求的路由。 edit 是一个合乎逻辑的选择。

    resource :shared, :only => [:edit], :controller => 'shared'
    

    注意:我认为SharedControllerSharedsController 更有意义,edit_shared_pathedit_shareds_path 更有意义,所以我必须在 routes.rb 中指定 :controller =&gt; 'shared'


    那么你只需要一个带有参数的 url 的链接。要将参数添加到路径中,您只需将它们添加到路径助手中,如下所示:

    edit_shared_path(:key => 'value')
    

    您可以通过以下方式在控制器中检索这些参数:

    params[:key]
    

    把它变成这样的链接:

    link_to 'Set Own to True for This Object', edit_shared_path(:object_id=>object.id, :own=>'true')
    

    注意:最好通过 AJAX 执行此操作,因此请务必设置 :remote=&gt;true。如果您不使用 AJAX,那么您需要在控制器中指定一个重定向,以便在触发此链接后应该加载哪个页面。


    对于我的管理菜单首选项链接,我需要一个具有两种可能状态的链接。我使用助手生成这些:

      # Shows Admin Menu Button
      def admin_toggle_button
        if session[:admin_menu] == :on
          link_to( 'Admin Tools', edit_shared_path(:admin_menu => :off), :remote=>true, :class => 'selected', :id => 'admin_toggle_button', :title => 'Hide Admin Menu' )
        else
          link_to( 'Admin Tools', edit_shared_path(:admin_menu => :on), :remote=>true, :id => 'admin_toggle_button', :title => 'Show Admin Menu' )
        end
      end
    

    在一个视图中,我只是使用admin_toggle_button 来调用它。如果你愿意,你可以做类似的事情,但它是可选的。

    我希望这能让你走上正轨,如果你有任何问题,请告诉我。


    编辑:根据您的评论:

    链接发出 GET 请求,这意味着您将执行 EDIT 操作。见:http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions

    另一个问题,你有resources :toys 而不是resource :shared(我用于此目的)。这意味着您的链接助手已经期望编辑特定的玩具,而不是处理单一资源。见:http://guides.rubyonrails.org/routing.html#singular-resources

    如果您将链接更改为:

    link_to 'Set Own', edit_toy_path(@toy, :owned=>'true'), :remote => true
    

    ... 并将控制器中的编辑操作设置为以下内容:

    def edit
      @toy = Toy.find(params[:id])
      @toy.owned = params[:owned]
      if @toy.save!
        head :ok
      else
        head :internal_server_error
      end
    end
    

    见:http://guides.rubyonrails.org/layouts_and_rendering.html#using-head-to-build-header-only-responses

    现在,请注意,您真的应该只使用 AJAX 链接执行此操作,并且通常不应该使用您的“真实”控制器执行此操作。原因是,现在这是唯一可以由 EDIT 处理的操作,因此您的正常 toys#edit 视图将不再起作用。

    您可以通过创建新操作和新路线来解决此问题,例如:

    resources :toys do
      member do
        get 'set_ownership'
      end
    end
    

    然后只需采用上面相同的方法并将其命名为set_ownership 而不是edit。即:

    class ToysController < ApplicationController
      ...
      def set_ownership
        ...
      end 
    end
    

    希望一切都有意义。

    【讨论】:

    • 谢谢,这很有帮助。我用更多细节更新了这个问题,以帮助你。抱歉,我从一开始就忽略了这些。现在,当我单击“拥有”链接时,它只会将我定向到编辑表单。我需要弄清楚如何完全提交表单并显示成功消息。任何想法。
    • 这对我有用,但我不得不将 get 'set_ownership' 切换为 put。
    • 有趣,你用的是:method=&gt;:put吗?很高兴无论哪种方式都有效。
    • 我是根据这个 [链接] (guides.rubyonrails.org/routing.html#singular-resources) 做的 - 放 = 更新操作。感谢您的帮助。
    【解决方案2】:

    link_to 方法正在调用的 edit_toy_path 方法将转到控制器内的 edit 操作。我猜你想要的不是update 方法。

    您的link_to 需要更改为:

    <%= link_to 'Set Own', toy_path(:id=>toy.id, :owned=>'true'), :method => :put %>
    

    但我质疑这种特殊的方法。我认为该变量不会在更新操作中正确更新,因为它没有被命名为 update_attributes 所期望的正确的 params[:toy] 对象。在我快速而肮脏的测试中,我无法正确地将其放入命名空间。

    当我遇到与您描述的情况类似的情况时,我通常会设置另一个操作,例如 toggle_ownership,然后我通过 link_to 使用 :remote =&gt; true 选项调用它。然后控制器根据需要切换属性。

    因此,我的路线看起来像:

    resources :toys do
      member do
        put :toggle_ownership
      end
    end
    

    我的观点看起来像

    <%= link_to 'Set Own', toggle_ownership_toy_path(toy.id), :method => :put %>
    

    控制器设置变量并返回一个更新页面相应部分的toggle_ownership.js.erb 文件。

    希望有帮助!

    【讨论】:

    • 感谢您提供的信息,这对这有很大帮助。
    猜你喜欢
    • 1970-01-01
    • 2015-02-16
    • 2016-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-24
    • 1970-01-01
    相关资源
    最近更新 更多