问题
Bizarre Rails problem.
I have a Book
entity and users can Love
a book.
All my other models are fine and passing all the tests but after generating the new Love
model and setting the fixtures, I am getting a ton of these errors out of the blue:
ActiveRecord::Fixture::FixtureError: table "books" has no column named "loves".
I somehow think it's to do with reserved keywords in Rails perhaps?
Is Love
a reserved keyword by any chance?
I did a search on this page:
https://reservedwords.herokuapp.com/
And the word love
yields no results.
Love Migration File
class CreateLoves < ActiveRecord::Migration[5.0]
def change
create_table :loves do |t|
t.references :book, foreign_key: true
t.references :sender, foreign_key: true
t.references :receiver, foreign_key: true
t.timestamps
end
end
end
Love Model
class Love < ApplicationRecord
belongs_to :book
belongs_to :sender, class_name: "User"
belongs_to :receiver, class_name: "User"
end
Love Fixtures
one:
book: one
sender: jim
receiver: sarah
two:
book: two
sender: sarah
receiver: jim
three:
book: three
sender: jim
receiver: tycus
Book Model
class Book < ApplicationRecord
belongs_to :author, class_name: "User"
has_and_belongs_to_many :genres
has_many :loves
end
Book Fixtures
one:
title: Back To The Future
adult_content: true
author: jim
published: false
genres: action, comedy, science_fiction
two:
title: Harry Potter and The Philosopher's Stone
adult_content: false
author: sarah
published: false
genres: action, fantasy
three:
title: Back To The Future 2
adult_content: true
author: jim
published: false
genres: action, comedy, science_fiction
four:
title: Back To The Future 3
adult_content: true
author: jim
published: false
genres: action, comedy, science_fiction
five:
title: Royal Guard
adult_content: true
author: chewedon
published: false
genres: action, romance, fantasy
Books Controller
class BooksController < ApplicationController
before_action :authenticate_user
after_action :verify_authorized, except: [:index, :create]
after_action :verify_policy_scoped, only: :index
def index
books = policy_scope(Book.all)
render json: books
end
def create
book = Book.new(book_params)
if book.save
render json: book, status: :created
else
render status: :unprocessable_entity
end
end
def show
book = Book.find_by(id: params[:id])
if book.present?
authorize book
render json: book
else
skip_authorization
render status: :not_found
end
end
def update
book = Book.find_by(id: params[:id])
skip_authorization and render status: :not_found and return unless book
authorize book
if book.update!(book_params)
render json: book
else
render status: :unprocessable_entity
end
end
def destroy
book = Book.find_by(id: params[:id])
skip_authorization and render status: :not_found and return unless book
authorize book
if book.destroy!
render status: :ok
end
end
private
def book_params
params.permit(:title, :adult_content, :published, :author_id, genre_ids: [])
end
end
Here are some of my other model and their test fixtures, they all pass the tests:
Chapter Fixtures
one:
title: Straw House
order: 1
content: First pig built a house out of straw
published: true
book: one
two:
title: Wooden House
order: 2
content: Second pig built a house out of wood
published: true
book: one
three:
title: Brick House
order: 3
content: Third pig built a house out of brick
published: false
book: one
four:
title: Hogwarts School of Wizardry
order: 1
content: They pushed their troller into nine and three quarters
published: false
book: two
Comment Fixtures
one:
content: Love this chapter
author: jim
book: one
chapter: one
two:
content: Hate this chapter
author: sarah
book: two
chapter: two
three:
content: Interesting chapter
author: tycus
book: one
chapter: one
Message Fixtures
one:
subject: Next Chapter
body: When will the next chapter be published?
sender_read: false
receiver_read: false
sender: jim
receiver: sarah
two:
subject: Film Adaptation
body: I would like to turn your story into a film
sender_read: false
receiver_read: false
sender: sarah
receiver: jim
three:
subject: Mind Blown
body: Where do you get all these ideas? I'll stalk you now!
sender_read: false
receiver_read: false
sender: tycus
receiver: jim
What could be the problem?
Update
If I comment out my Love Fixtures:
# one:
# book: one
# sender: jim
# receiver: sarah
#
# two:
# book: two
# sender: sarah
# receiver: jim
#
# three:
# book: three
# sender: jim
# receiver: tycus
I get new test errors:
Error:
BooksControllerTest#test_book_show_-_should_show_book_info:
NameError: uninitialized constant Book::Lofe
app/controllers/books_controller.rb:26:in `show'
test/controllers/books_controller_test.rb:63:in `block in <class:BooksControllerTest>'
Where the heck did Lofe
come from?
I quadruple checked my spelling of Love. I even did an entire project search for word "Lofe" and it doesn't show any search results matching.
回答1:
Wild guess, but I think, it's because of how Inflector treats your has_many :loves
line.
I think it assumes, that singular from loves
is lofe
, thus the error, because it tries to resolve the constant Lofe
in the scope of Book
class.
To override the default behaviour, see the very first block of code from the docs:
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.irregular 'octopus', 'octopi'
# for your case it's
inflect.irregular 'love', 'loves'
end
回答2:
@andreyDeineko is right, if you do "loves".singularize
you get lofe
You can override how rails determines singular / plural in your environment or application rb
ActiveSupport::Inflector.inflections do |inflect|
inflect.irregular 'love', 'loves'
end
来源:https://stackoverflow.com/questions/40846420/activerecordfixturefixtureerror-table-books-has-no-column-named-loves