简体   繁体   中英

Rails has_many :through validation issue

I've been fighting using the Rails has_many :through all week long. Initially I had issues getting the collection_select form helper to save .

I eventually got that to work, and moved to trying to get a json post request to support adding a new Author. I modeled the json after the request params created by using the now functioning form. It worked the very first time I made the request with these params:

{
    "author": {
        "name": "Author Name",
        "post_ids": [
            "1", "2"
        ]
    }
}

I started testing my validations, and ran into an issue where if a post_id is sent that does not exist in the database Rails will bomb on the @author.new method:

Request:

{
    "author": {
        "name": "Author Name",
        "post_ids": [
            "23"
        ]
    }
}

Error:

ActiveRecord::RecordNotFound (Couldn't find Post with 'id'=23):
  app/controllers/authors_controller.rb:32:in `create'

Controller

  def create
    @author = Author.new(author_params)

    respond_to do |format|
      if @author.save
        format.html { redirect_to @author, notice: 'Author was successfully created.' }
        format.json { render :show, status: :created, location: @author }
      else
        format.html { render :new }
        format.json { render json: @author.errors, status: :unprocessable_entity }
      end
    end
  end

It is bombing on this line

@author = Author.new(author_params)

I attempted to use validations to make sure the id exists, but it's erroring before it ever makes it to validations. It seems that rails is creating the associations in the new method.

How can I catch this? I've written a check before the Author.new call to make sure the author_ids sent exist, but if rails provides this ability I'd like to be able to use the built in functionality to catch it and send it back with other validation messages instead.

Models:

class Author < ActiveRecord::Base
  has_many :post_authors
  has_many :posts, :through => :post_authors
  accepts_nested_attributes_for :post_authors
end

class Post < ActiveRecord::Base
end

class PostAuthor < ActiveRecord::Base
  belongs_to :post
  belongs_to :author
end

Schema

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

  create_table "authors", force: :cascade do |t|
    t.string   "name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "post_authors", force: :cascade do |t|
    t.integer  "post_id"
    t.integer  "author_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

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

end

Thanks for any help.

Validation Attempt

I put the following validation below in all 3 models. I added breakpoints and the log messages. None of them hit before the error occurs, so at this point I'm getting nowhere with validations happening to even be able to make a check.

class Author < ActiveRecord::Base
  has_many :post_authors
  has_many :posts, :through => :post_authors
  accepts_nested_attributes_for :post_authors

  validate :post_exists

  def post_exists
    Rails.logger.debug("Validate")
  end
end

According to the rails guide validations are only triggered when following methods are called:

  • create
  • create!
  • save
  • save!
  • update
  • update!

So I reckon that your best chance would be to rescue the ActiveRecord::RecordNotFound in your controller as it is explained in this question:

how to handle ActiveRecord::RecordNotFound in rails controller?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM