Ruby 在 Rails。通过视图更改控制器的变量并呈现更新的视图

Ruby On Rails. Change controller's variable through view and render updated view

我在 RoR 甚至网络编程方面都是初学者。所以我想我的问题对很多开发者来说太简单了!

我正在实施简单的周日历,它应该有日期名称和两个 "buttons" - 'next week' 和 'previous week'。这就是开始!

我有带索引操作的控制器:

    def index

      @today = Date::today
      @monday = @today.beginning_of_week
      @sunday = @today.end_of_week

      @currentweek = @monday..@sunday    
   end

和其他两个操作:

  def go_next_week
      @monday = @sunday + 1
      @sunday = @monday.end_of_week
  end

  def go_prev_week
      @sunday = @monday - 1
      @monday = @sunday.beginning_of_week
  end

索引查看代码:

<div class="wrapper">
  <table class="data">
    <thead>
    <tr class="month-names">      
      <td><%= form_tag(work_days_go_prev_week_path, method: "get") do %>
            <%= submit_tag(l(("workdays_show_prev" + period).to_sym)) %>
        <% end %>
      </td>
      <td><%= render :partial => 'days_names_header' %></td>
      <td><%= form_tag(work_days_go_next_week_path, method: "get") do %>
            <%= submit_tag(l(("workdays_show_next" + period).to_sym)) %>
        <% end %>
      </td>
    </tr>
    </thead>
  </table>
</div>

路由文件:

RedmineApp::Application.routes.draw do
  match 'work_days/go_next_week'            ,:to => 'work_days#go_next_week',           via: [:get]
  match 'work_days/go_prev_week'            ,:to => 'work_days#go_prev_week',           via: [:get]
  match 'work_days/(:action(/:id))',via: [:get], :controller => 'work_days'
end

短期内该阶段的主要目标是:

此代码无效。单击 'Previous month' 按钮时,我在日志中遇到这样的错误:

Started GET "/work_days/go_prev_week?tf8=%E2%9C%93&commit=Previous+week" for 127.0.0.1 at 2015-12-09 14:00:27 +0600 Processing by WorkDaysController#go_prev_week as HTML Parameters: {"utf8"=>"✓","commit"=>"Previous week"} Current user: admin (id=1) Completed 500 Internal Server Error in 3ms (ActiveRecord: 0.2ms)

NoMethodError (undefined method `-' for nil:NilClass)

您可能应该在 before_action.

中初始化这些实例变量

例如:

class MyController < ActionController
  before_action :set_dates

  def index
    # ... Your index implementation
  end

  def go_next_week
    @monday = @sunday + 1
    @sunday = @monday.end_of_week
  end

  def go_prev_week
    @sunday = @monday - 1
    @monday = @sunday.beginning_of_week
  end

  private

  def set_dates
    @today = Date::today
    @monday = @today.beginning_of_week
    @sunday = @today.end_of_week

    @currentweek = @monday..@sunday
  end
end

以这种方式,日期将在每个动作中被初始化。不过要小心!上面的这个实现只允许再往前一周。例如,要使每周都能正常工作,您必须提供 param 当前一周。

我希望这对您有所帮助,如果您需要更多信息,欢迎您。 :)

您在操作中使用了@monday go_prev_week,您没有在方法中计算@monday,@monday 是一个实例变量,其默认值为nil。

您有两种方法可以解决这个问题 -

第一-

  def go_prev_week
     index
     @sunday = @monday - 1
     @monday = @sunday.beginning_of_week
  end

其次 - 计算@monday

  def go_prev_week
     @today = Date::today
     @monday = @today.beginning_of_week
     @sunday = @monday - 1
     @monday = @sunday.beginning_of_week
  end

你必须在动作中做同样的事情 go_next_week

I'm very beginner in RoR and even in web-programming.

欢迎光临!


你的问题是你用 @instance_variables 填充你的控制器操作,它们相互依赖:

def go_next_week
  @monday = @sunday + 1           # needs @sunday
  @sunday = @monday.end_of_week   # needs @monday
end

在旧式编程中,这可能会导致无法识别的引用错误或堆栈溢出错误,通常是由于无限 recursion.

错误证实了这一点:

undefined method `-' for nil:NilClass

Ruby 与大多数其他语言的不同之处在于它将未声明的变量分配给 NilClass 对象。这使得开发人员很难确定错误 - 基本上,如果您收到 undefined method for NilClass,那是因为您没有声明变量。

--

解决方法是将您尝试操作的数据获取到 class 的实例中。这可以通过 before_action 过滤器来实现:

#app/controllers/work_days_controller.rb
class WorkDaysController < ApplicationController
   before_action :set_dates

   def index
      #@today, @monday, @sunday will be available in here.
   end

   private

   def set_dates
      @today = Date::today
      @monday = @today.beginning_of_week
      @sunday = @today.end_of_week
   end
end 

您还可以改进路线以使用 resources 指令:

#config/routes.rb
resources :work_days do
   get :go_next_week, on: :collection
   get :go_prev_week, on: :collection
end

您似乎希望拥有相同的控制器操作和视图,但仅限于其他日期。

如果是这样,我会向您推荐这样的东西:

class MyController < ApplicationController
  before_action :set_date

  def index
  end

  private

  def set_date
    if params[:week].present? && params[:year].present?
      @today = Date.commercial(params[:year].to_i, params[:week].to_i)
    end

    @today ||= Date::today # <= Just use date today if it's not set already

    @monday = @today.beginning_of_week
    @sunday = @monday - 1
    @monday = @sunday.beginning_of_week
  end
end

路线:

RedmineApp::Application.routes.draw do
  get 'calendar' => 'my_controller#index', as: :index_action
end

然后您可以将 next/previous 链接添加到您的视图,如下所示:

<%= link_to "Next", index_action_path(year: @today.year, week: @today.cweek + 1) %>
<%= link_to "Previous", index_action_path(year: @today.year, week: @today.cweek - 1) %>

我还没有测试过这个实现,但它应该可以工作。无论如何你都应该添加测试。

但是你应该明确检查参数是否正确。例如,如果周数在 1 到 52 的范围内,依此类推。否则,如果周超出范围,它将引发异常。

也尽量不要将逻辑放在视图中,而是放在辅助方法中。

我希望这对您有所帮助,祝您编码愉快。 :)