Search code examples
ruby-on-railsruby-on-rails-5active-model-serializers

Rails 5 inverse of not working


I'm trying to return JSON API where a show action will

render json: user, include [:books, :friends, :comments]

Problem is, if I try to use the inverse_of in my User and Book model classes like this:

User Serializer

class UserSerializer < ActiveModel::Serializer
  ...
  has_many :friends
  has_many :books, inverse_of: :author
  ...
end

Book Serializer

class BookSerializer < ActiveModel::Serializer
  ...
  belongs_to :author, class_name: "User", inverse_of: :books
  ...
end

I get an error:

ActiveRecord::StatementInvalid (SQLite3::SQLException: no such column: books.user_id: SELECT "books".* FROM "books" WHERE "books"."user_id" = ?):

If I remove the inverse_of and has_many from my User serializer, then I don't get any errors, but then the JSON being returned does not contain the included association.

Likewise, the same happens between Comment and User models.

Am I doing something wrong ?

My DB Schema for my two models are:

User Schema

create_table "users", force: :cascade do |t|
  t.string   "first_name"
  t.string   "last_name"
  t.string   "username"
  t.string   "email"
  t.string   "password_digest"
  t.boolean  "banned"
  t.integer  "role_id"
  t.datetime "created_at",                           null: false
  t.datetime "updated_at",                           null: false
  t.string   "photo"
  t.boolean  "email_confirmed",      default: false
  t.string   "confirm_token"
  t.string   "password_reset_token"
  t.boolean  "show_private_info",    default: false
  t.boolean  "show_contact_info",    default: false
  t.index ["role_id"], name: "index_users_on_role_id"
end

Book Schema

create_table "books", force: :cascade do |t|
  t.string   "title"
  t.boolean  "adult_content"
  t.integer  "author_id"
  t.datetime "created_at",    null: false
  t.datetime "updated_at",    null: false
  t.boolean  "published"
  t.string   "cover"
  t.text     "blurb"
  t.index ["author_id"], name: "index_books_on_author_id"
end

When I went to generate my Book model with:

rails generate model books ... author:references

It created this migration file:

class CreateBooks < ActiveRecord::Migration[5.0]
  def change
    create_table :books do |t|
      t.string :title
      t.boolean :adult_content
      t.references :author, foreign_key: true

      t.timestamps
    end
  end
end

I assume that includes the necessary foreign key setup...


Solution

  • Try to change this line in your User model(user.rb):

    has_many :books, inverse_of: :author
    

    to

    has_many :books, inverse_of: :author, foreign_key: :author_id
    

    You need to tell rails what foreign_key you used if it's not the default one.And the association should be declared in your models, not serializers. In serializer you are adding keys by "has_many", inverse_of does't works here.