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

时间:2015-12-09 08:07:12

标签: ruby-on-rails ruby redmine

我是RoR的初学者,甚至是网络编程。所以我想我的问题对很多开发人员来说都很容易!

我正在实施简单的周历,它应该有一天的名字和两个“按钮” - “下周”和“前一周”。这一切都是为了开始!

我有控制器的索引操作:

    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

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

  • Controller有一个Date变量'monday','sunday'和Range 'currentweek'

  • 索引视图显示根据变量

  • 的天数表
  • 索引视图有2个“按钮”:“下周”和“上周”

  • 单击此按钮可更改Controller的变量

  • 索引视图应该使用已更改的Controller变量“刷新”

此代码无效。点击“上个月”按钮时,我在日志中出现了这样的错误:

  

开始GET   “/ work_days / go_prev_week?tf8 =%E2%9C%93&amp; commit = Previous + week”for   127.0.0.1 at 2015-12-09 14:00:27 +0600由WorkDaysController处理#go_prev_week作为HTML参数:   {“utf8”=&gt;“✓”,“commit”=&gt;“上周”}当前用户:admin(id = 1)   在3ms内完成500内部服务器错误(ActiveRecord:0.2ms)

     

NoMethodError(未定义的方法` - '代表nil:NilClass)

4 个答案:

答案 0 :(得分:3)

  

我是RoR的初学者,甚至是网络编程。

欢迎!

您的问题是,您使用@instance_variables填充控制器操作,这些操作相互依赖:

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

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

错误证实了这一点:

  

未定义的方法` - '为nil:NilClass

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

-

修复方法是将您尝试操作的数据导入到类的实例中。这可以通过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

答案 1 :(得分:1)

您可能应该在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当前周。

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

答案 2 :(得分:1)

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

如果是这种情况,我建议您这样:

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

然后您可以添加下一个/上一个链接到您的视图,如下所示:

<%= 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的范围内,依此类推。否则,如果周超出范围,它将引发异常。

还要尝试不将逻辑放入视图中,而是放在辅助方法中。

我希望这有助于编码。 :)

答案 3 :(得分:0)

你在动作go_prev_week中使用@monday,你没有在方法中计算@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

中做同样的事情