未定义的方法或我的Active Record错误

时间:2018-03-22 21:36:07

标签: ruby-on-rails ruby-on-rails-5

很抱歉,如果我的问题很愚蠢,但Rails对我来说很新。我制作了两个型号和两个控制器。我的问题是在我制作了第二个模型并添加了对第一个模型的引用后开始的。

class SentencesController < ApplicationController
    before_action :find_story

    def create      
        @sentence = find_story.sentences.build(sentence_params)
        if @sentence.save
           flash[:success] = "You wrote the continuation!"
           render 'stories/show'
        else
          render 'stories/show'
        end
    end

  private

    def sentence_params
      params.require(:sentence).permit(:content)
    end

    def find_story
        @story = Story.find(params[:id])
    end
end

和此:

class StoriesController < ApplicationController 

........

    def show
        @story = Story.find(params[:id])
        @sentence = @story.sentences.build
    end 

.........


end

我在定义实例变量@story = Story.find(params [:id])时遇到问题。错误:SentencesController #create中的ActiveRecord :: RecordNotFound。我尝试了很多种组合。

这是我的迁移文件:

class CreateStories < ActiveRecord::Migration[5.1]
  def change
    create_table :stories do |t|
      t.string :title
      t.text :content

      t.timestamps
    end
  end
end

class CreateSentences < ActiveRecord::Migration[5.1]
  def change
    create_table :sentences do |t|
      t.text :content
      t.references :story, foreign_key: true

      t.timestamps
    end
    add_index :sentences, [:story_id, :created_at]
  end
end

我做错了什么?

编辑(路线):

Rails.application.routes.draw do
    root 'stories#index'
    get 'stories/show'
  get 'stories/new'
  resources :stories
  resources :sentences, only: [:create]
end

和架构:

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

  create_table "sentences", force: :cascade do |t|
    t.text "content"
    t.integer "story_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["story_id"], name: "index_sentences_on_story_id"
  end

  create_table "stories", force: :cascade do |t|
    t.string "title"
    t.text "content"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

end

2 个答案:

答案 0 :(得分:3)

As stated in the comments, you probably want your routes to look something like:

resources :stories do 
  resources :sentences, only: [:create]
end

Which will give you:

 story_sentences POST   /stories/:story_id/sentences(.:format)   sentences#create
         stories GET    /stories(.:format)                       stories#index
                 POST   /stories(.:format)                       stories#create
       new_story GET    /stories/new(.:format)                   stories#new
      edit_story GET    /stories/:id/edit(.:format)              stories#edit
           story GET    /stories/:id(.:format)                   stories#show
                 PATCH  /stories/:id(.:format)                   stories#update
                 PUT    /stories/:id(.:format)                   stories#update
                 DELETE /stories/:id(.:format)                   stories#destroy

Which you might use something like:

<%= form_tag story_sentences_path(@story) do %>
  ...
<% end %>

Then, as Matt said, change your find to:

@story = Story.find(params[:story_id])

答案 1 :(得分:0)

There are a couple of reasonable ways you can find the story in your sentences controller.

  1. You can add a story_id field to your form and submit it as a param along with the sentence content. Just make sure to add it to sentence_params in the controller so it's not ignored.

    def sentence_params
      params.require(:sentence).permit(:content, :story_id)
    end
    

    And then you'll need to update your find_story method in the controller to:

    @story = Story.find(sentence_params[:story_id])
    
  2. You can set up nested resources in your routes file (where the sentences resource is nested within the stories resource). That will give you access to the story_id from the route itself (ie. you wouldn't need to submit the story_id through the form).

    And if you go this way, you'll also need to tweak the find_story method in the controller, but this time it should be:

    @story = Story.find(params[:story_id])