【问题标题】:Rails 6: How can I use `button_to` in a presenter class?Rails 6:如何在演示者类中使用`button_to`?
【发布时间】:2019-08-14 11:50:01
【问题描述】:

我有一个演示者:

class PresentedOrderService
  include Rails.application.routes.url_helpers

  attr_reader :service, :order
  delegate :date, to: :service

  def initialize(service, order)
    @service = service
    @order = order
  end

  def order?
    service.date == order.delivery_date
  end

  def confirmation_text
    'Click ok to confirm your order.'
  end
end

我有一个有条件地显示按钮的视图:

<% if service.order? %>
  <div class="badge badge-success">Your order is booked for this date</div>
<% else %>
  <%= button_to service.button_text,
      arrange_delivery_path(
          id: service.order.id,
          date: service.date,
        ),
      data: {
              confirm: service.confirmation_text
            }
  %>
<% end %>

作为重构步骤,我想将按钮移动到演示器中:

<% if service.order? %>
  <div class="badge badge-success">Your order is booked for this date</div>
<% else %>
  <%= service.button %>
<% end %>
class PresentedOrderService
#...
  def button
    helpers.button_to(
      button_text,
      arrange_delivery_path(
        id: order.id,
        date: date,
      ),
      data: { confirm: confirmation_text }
    )
  end

但是,这不起作用。我在控制台中收到此错误错误:

ActionView::Template::Error (undefined method `protect_against_forgery?' for nil:NilClass):
    18:               <% if service.order? %>
    19:                 <div class="badge badge-success">Your order is booked for this date</div>
    20:               <% else %>
    21:                 <%= service.button
    22:                 %>
    23:               <% end %>
    24:             </div>

app/controllers/orders_controller.rb:21:in `button'
app/views/orders/edit.html.erb:21

我可以看到问题来自使用button_to 方法,因为当我将代码更改为时看到相同的错误:

  def button
    helpers.button_to 'Home', Rails.application.routes.url_helpers.root_path
  end

当它显示nil:NilClass 时,我不确定该错误指的是什么。这是哪里来的?

我需要采取哪些步骤才能使button_to 在演示者中工作。有可能吗?

更新

这是控制器:

class OrdersController < ApplicationController
  def edit
    @order = Order.find(params[:id])
    @services = ServiceDate.all.map { |service| PresentedOrderService.new(service, @order) }
  end

  def update
    if @order.update(delivery_date: params[:date])
      flash[:success] = 'Your delivery has been booked'
      redirect_to root_path
    else
      flash.now[:warning] = 'Error. Please try again or contact support'
      render 'edit'
    end
  end
end

【问题讨论】:

    标签: ruby-on-rails ruby


    【解决方案1】:

    这似乎与按钮无关。 protect_against_forgery? 是一种为 CSRF 攻击启用安全性的方法。通常,在使用 Rails 作为 API 模式时会出现此错误,因为 Controllers 不是从 ApplicationController 扩展而来,而是从 ActionController 扩展而来。检查是否是您的情况。

    【讨论】:

    • 我的控制器继承了ApplicationController。如果是这种情况,我的演示者类应该扩展一些东西吗?
    • 你能在答案中添加ApplicationController代码吗?
    • 我已将其添加到原帖底部。
    • 试试这个:在 application_controller.rb class ApplicationController &lt; ActionController::Base protect_from_forgery with: :exception end
    • 抱歉,我没有更多信息。也许是因为 Rails 6 仅在候选版本中可能会有一些错误。尝试在 github/rails 中查找您的问题,如果没有看到,请报告。
    猜你喜欢
    • 2016-09-05
    • 2016-02-24
    • 1970-01-01
    • 1970-01-01
    • 2015-03-09
    • 1970-01-01
    • 1970-01-01
    • 2022-07-03
    • 1970-01-01
    相关资源
    最近更新 更多