【问题标题】:Working in rails console but getting : "NoMethodError in Workouts#index (undefined method `movements' for nil:NilClass)"在rails控制台中工作但得到:“Workouts#index中的NoMethodError(nil:NilClass的未定义方法'movements')”
【发布时间】:2016-11-13 13:25:20
【问题描述】:

这两天我一直在搜索这些论坛,最后放弃了。我一直在开发一个 Rails 应用程序,您可以在其中上传锻炼,然后让其他人查看它们并下载任何附加的 Excel 文件。我的表格是这样的

  '<div class="form-group">
     <div class="control-label col-md-2">
                <%= f.label :name, "Workout name" %><br>
              </div>
              <div class="col-md-10">
                <%= f.text_field :name, class: "form-control" %>
              </div>
            </div>
            <div class="form-group">
              <div class="control-label col-md-2">
                <%= f.label :summary, "Summary", placeholder: "Who's this for? what experience level? Athletes or Bodybuilders etc"  %>
              </div>
              <div class="col-md-10">
                <%= f.text_area :summary, class: "form-control", rows: 10%>
              </div>
            </div>
          <div class="clearfix">
            <div class="col-lg-3 col-md-6">
            <%= f.label :Movement %>
              <%= f.fields_for :movements do |movement| %>
                <%= render 'movement_fields', f: movement %>
            <% end %>
                <div class="links">
                  <%= link_to_add_association 'Add movement', f, :movements, class: "pull-right d-inline-block btn btn-primary add-button" %>
                  </br>
                  </br>
                </div>
            </div>
            <div class="col-lg-3 col-md-6">
                 <%= f.label :Reps %>
                    <%= f.fields_for :reps do |rep| %>
                      <%= render 'rep_fields', f: rep %>
                    <% end %>
                <div class="links">
                  <%= link_to_add_association 'Add Reps', f, :reps, class: "pull-right d-inline-block btn btn-primary add-button" %>
                </br>
                </br>
                </div>
            </div>
            <div class="col-lg-3 col-md-6">
            <%= f.label :Sets %>
                    <%= f.fields_for :zets do |zet| %>
                      <%= render 'zet_fields', f: zet %>
                    <% end %>
                <div class="links">
                  <%= link_to_add_association 'Add Set', f, :zets, class: "pull-right d-inline-block btn btn-primary add-button" %>
                </div>
                  </br>
                  </br>
            </div>
            <div class="col-lg-3 col-md-6">
                 <%= f.label :Weights %>
                    <%= f.fields_for :weights do |weight| %>
                      <%= render 'weight_fields', f: weight %>
                    <% end %>
                <div class="links">
                  <%= link_to_add_association 'Add weight', f, :weights, class: "pull-right d-inline-block btn btn-primary add-button" %>
                </div>
                  </br>
                  </br> 
            </div>
            <strong>Upload image: </strong>
                <span class="picture">
                    <%= f.file_field :attachment %>
                </span>
          </div>

            <div class="form-group">
              <div class="col-md-offset-2 col-md-10">
                <%= f.submit class: "btn btn-success btn-lg" %>
              </div>
            </div>
          <% end %>
        </div>
      </div>
    </div>`

这似乎将我需要的所有内容上传到数据库,因为当我浏览条目时,它似乎有我需要的数据,即,运动的锻炼 ID 等。

这是 schema.rb

# Deleted some other columns in this that are in the app that aren't relevant to the post to reduce the amount of text. Exercises column is from another element in the app that works that i used basically the exact same method in creating. 

ActiveRecord::Schema.define(version: 20161113011850) do


  create_table "exercises", force: :cascade do |t|
    t.integer  "duration_in_min"
    t.text     "workout"
    t.date     "workout_date"
    t.integer  "user_id"
    t.datetime "created_at",      null: false
    t.datetime "updated_at",      null: false
  end

  add_index "exercises", ["user_id"], name: "index_exercises_on_user_id"

  create_table "movements", force: :cascade do |t|
    t.string   "name"
    t.integer  "exercise_id"
    t.integer  "workout_id"
    t.datetime "created_at",  null: false
    t.datetime "updated_at",  null: false
    t.integer  "workout_id"
  end

  add_index "movements", ["exercise_id"], name: "index_movements_on_exercise_id"
  add_index "movements", ["workout_id"], name: "index_movements_on_workout_id"


  create_table "reps", force: :cascade do |t|
    t.integer  "amount"
    t.integer  "exercise_id"
    t.integer  "workout_id"
    t.datetime "created_at",  null: false
    t.datetime "updated_at",  null: false
  end

  add_index "reps", ["exercise_id"], name: "index_reps_on_exercise_id"
  add_index "reps", ["workout_id"], name: "index_reps_on_workout_id"

  create_table "reviews", force: :cascade do |t|
    t.text     "body"
    t.integer  "user_id"
    t.integer  "recipe_id"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "users", force: :cascade do |t|
    t.string   "username"
    t.string   "email",                  default: "",    null: false
    t.string   "encrypted_password",     default: "",    null: false
    t.string   "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.integer  "sign_in_count",          default: 0,     null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.string   "current_sign_in_ip"
    t.string   "last_sign_in_ip"
    t.datetime "created_at",                             null: false
    t.datetime "updated_at",                             null: false
    t.string   "first_name"
    t.string   "last_name"
    t.boolean  "admin",                  default: false
  end

  add_index "users", ["email"], name: "index_users_on_email", unique: true
  add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true

  create_table "weights", force: :cascade do |t|
    t.integer  "kilogram"
    t.integer  "workout_id"
    t.integer  "exercise_id"
    t.datetime "created_at",  null: false
    t.datetime "updated_at",  null: false
  end

  add_index "weights", ["exercise_id"], name: "index_weights_on_exercise_id"
  add_index "weights", ["workout_id"], name: "index_weights_on_workout_id"

  create_table "workouts", force: :cascade do |t|
    t.string   "name"
    t.text     "summary"
    t.integer  "user_id"
    t.string   "attachment"
    t.datetime "created_at",      null: false
    t.datetime "updated_at",      null: false
    t.integer  "duration_in_min"
  end

  create_table "zets", force: :cascade do |t|
    t.integer  "quantity"
    t.integer  "exercise_id"
    t.integer  "workout_id"
    t.datetime "created_at",  null: false
    t.datetime "updated_at",  null: false
  end

  add_index "zets", ["exercise_id"], name: "index_zets_on_exercise_id"
  add_index "zets", ["workout_id"], name: "index_zets_on_workout_id"

end

还有模型锻炼.rb

类锻炼

  has_many :movements
  has_many :reps
  has_many :zets
  has_many :weights  

  accepts_nested_attributes_for :movements,
                                                            reject_if: proc { |attributes| attributes['name'].blank? },
                                                            allow_destroy: true
    accepts_nested_attributes_for :reps,
                                                            reject_if: proc { |attributes| attributes['amount'].blank? },
                                                            allow_destroy: true
  accepts_nested_attributes_for :zets,
                                                            reject_if: proc { |attributes| attributes['quantity'].blank? },
                                                            allow_destroy: true
    accepts_nested_attributes_for :weights,
                                                            reject_if: proc { |attributes| attributes['kilogram'].blank? },
                                                            allow_destroy: true

  validates :name, presence: true
  validates :summary, presence: true
  validates :movements, presence: true
  validates :reps, presence: true
  validates :zets, presence: true
  validates :weights, presence: true
end

和控制器锻炼控制器.rb

 class WorkoutsController < ApplicationController
      before_action :set_workout, only: [:edit, :update, :show, :like, :review]
      before_action :authenticate_user!, except: [:show, :index, :like, :search]
      before_action :require_same_user, only: [:edit, :update]
      before_action :admin_user, only: :destroy

  def index
    @workouts = Workout.all
  end

  def show
    @random_workout = Workout.where.not(id: @workout).order("RANDOM()").first(3)
  end

  def new
    @workout = Workout.new
  end

  def create
    @workout = Workout.new(workout_params)
    @workout.user = current_user

    if @workout.save
      flash[:success] = "Your workout was created successfully!"
      redirect_to workouts_path
    else
      render :new
    end
  end

  def edit

  end

  def update
    if @workout.update(workout_params)
      flash[:success] = "Your workout was update success"
      redirect_to workout_path(@workout)
    else
      render :edit
    end
  end

  def destroy
    Workout.find(params[:id]).destroy
    flash[:success] = "Workout Deleted"
    redirect_to workouts_path
  end

  def review
    review = Review.create(body: params[:body], user: current_user, workout: @workout)
    if review.valid?
      flash[:success] = "Thank you for reviewing this workout"
    else
      flash[:danger] = "Review failed to post"
    end
    redirect_to :back
  end

  def deletereview
    Review.find(params[:revid]).destroy
    flash[:success] = "Review deleted"
    redirect_to :back
  end

  private

    def workout_params
        params.require(:workout).permit(:name, :summary, :attachment, :user_id, movements_attributes: [:id, :name, :_destroy], reps_attributes: [:id, :amount, :_destroy], zets_attributes: [:id, :quantity, :_destroy], weights_attributes: [:id, :kilogram, :_destroy],)
    end

    def set_workout
      @workout = Workout.find(params[:id])
    end

    def require_same_user
      if current_user != @recipe.user and !current_user.admin?
        flash[:danger] = "You can only edit your own recipes"
        redirect_to recipes_path
      end
    end


    def admin_user
      redirect_to recipes_path unless current_user.admin?
    end

end

最后是 index.html.erb

  <thead>
    <tr>
      <th>Name</th>
      <th>Summary</th>
      <th>Attachment</th>
      <th>Exercises</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @workouts.each do |workout| %>
      <tr>
        <td><%= workout.name %></td>
        <td><%= truncate(workout.summary, length: 350) %><%= link_to 'click to see workout', workout_path(workout)%></td>
        <td><%= link_to "Download Workout", workout.attachment_url %>%></td>
        <td><%= link_to 'Show', workout %></td>
    <% end %>
    <% @workout.movements.each do |movement| %>
        <td>
          <ol>
            <li>
              <%= movement.name %>
            </li>
          </ol>
    <%end%>
    <% @workout.reps.each do |rep| %>
        <td>
          <ol>
            <li>
              <%= rep.amount %>
            </li>
          </ol>
    <%end%>

对不起所有的文字,我只是想在第一轮包含所有内容。而且我知道这个问题已经被问死了,我很抱歉,因为无法从已经回答的问题中解决这个问题,但是,真的希望弄清楚为什么我会得到这个错误。

锻炼中的 NoMethodError#index 显示 /home/ubuntu/workspace/app/views/workouts/index.html.erb 其中第 24 行提出:

nil:NilClass 的未定义方法 `movements'

正如我所提到的,我现在已经两次实现了几乎完全相同的功能,在应用程序中的其他 2 个功能上,它们的工作方式几乎与“应该”完全相同。所以我很困惑:(

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-4 controller schema


    【解决方案1】:

    你得到了未定义的方法,因为你没有声明变量 @workout - 这意味着 @workout 是 nil 并且你试图在那个 nil 对象上调用 movements

    您确实有一个变量@workouts,但我假设这不是您想要的对象...我认为您想使用workout 中声明的@workout.each |workout|,这会导致第二个问题。在尝试使用@workout(应该是workout)之前,您将结束该块

    这就是你所拥有的:

    <% @workouts.each do |workout| %>
       # do stuff
    <% end %>
    # variable workout now out of scope
    <% @workout.movements.each do |movement| %>
    

    您应该将实例变量 @workout 更改为局部变量 workout 并将其嵌入到您的每个块中。

    <% @workouts.each do |workout| %>
       # do stuff with workout object here
      <% workout.movements.each do |movement| %>
        # do stuff with movement object here
      <% end %>
      <% workout.reps.each do |rep| %>
        # do stuff with rep object here
      <% end %>
      #etc ... etc...
    <% end %>
    

    【讨论】:

    • 嘿 Henners,感谢您的反馈。我已经实现了你的解决方案,所以它看起来像这样 &lt;% workout.movements.each do |movement| %&gt; &lt;td&gt; &lt;ul&gt; &lt;li&gt;&lt;% movement.name %&gt;&lt;/li&gt; &lt;/ul&gt; &lt;/td&gt; &lt;% end %&gt; &lt;% workout.reps.each do |rep| %&gt; &lt;td&gt; &lt;ul&gt; &lt;li&gt;&lt;% rep.amount %&gt;&lt;/li&gt; &lt;/ul&gt; &lt;/td&gt; &lt;% end %&gt; 但我最终得到了这个错误“未定义的局部变量或方法 `workout' for #
    • 它指的是第27行,即&lt;% workout.movements.each do |movement| %&gt;
    • 那是在&lt;% @workouts.each do |workout| %&gt; 块内吗?
    • 哦,我明白了,我对此感到抱歉。修复它已经停止了我所有的错误,但我的条目都没有出现?生成了正确数量的
    • ,但它们旁边没有文本。我已经编辑了原始索引页面以显示我现在得到的。再次感谢!!
  • 您没有使用作业 - 您只是在评估它 - 使用
  • 【解决方案2】:

    您试图在@workout 变量上调用运动关联,因为您没有在控制器操作中声明任何位置。所以不会引发方法错误异常。 如果你想循环每个锻炼的动作,你需要进入循环并调用它的关联。

    <% @workouts.each do |workout| %>
       <% workout.movements.each do |movement| %>
         <%= movement.name %>
       <% end %>
     <% end %>
    

    【讨论】:

    • 嗨,阿迪塔,感谢您的回复。我已经实现了你的解决方案,所以它看起来像这样 &lt;% workout.movements.each do |movement| %&gt; &lt;td&gt; &lt;ul&gt; &lt;li&gt;&lt;% movement.name %&gt;&lt;/li&gt; &lt;/ul&gt; &lt;/td&gt; &lt;% end %&gt; &lt;% workout.reps.each do |rep| %&gt; &lt;td&gt; &lt;ul&gt; &lt;li&gt;&lt;% rep.amount %&gt;&lt;/li&gt; &lt;/ul&gt; &lt;/td&gt; &lt;% end %&gt; 但我最终得到了这个错误“未定义的局部变量或方法 `workout' for #
    • 您好 Schimdt,在您的 index.html.erb 页面中,您是否将上述代码放入此循环中? &lt;% @workouts.each do |workout| %&gt; # your code here &lt;% end %&gt;
    • 嘿阿迪塔,我做了(经过几次尝试>。 的数量是正确的,但是它们旁边没有数据。
    • 尝试在 Rails 控制台中玩耍。检查是否有输出。如果您想动态调试,请尝试使用 gem 'pry'。阅读文档。使用这些我希望你能解决问题。
    • Aditya Y 我最后做了
    猜你喜欢
    相关资源
    最近更新 更多
    热门标签