ActiveRecord更改关联的名称?



我正在用ActiveRecord构建数据库,其中有一个Users表、一个Recipes表和一个RecipeSaves表(后者是前两个的连接表)。当我尝试使用Rails控制台查看特定用户的recipe_saved时,得到以下消息:

Rails couldn't find a valid model for RecipeSafe association. Please provide the :class_name option on the association declaration. If :class_name is already provided, make sure it's an ActiveRecord::Base subclass. (NameError)

我搜索了整个app,还有"安全"这个词。从来没有出现在任何地方,所以我不知道"RecipeSafe"来自。如果我之前犯了一个错别字,我确保重新保存了所有文件,并且删除并重新创建了数据库。什么好主意吗?

class Recipe < ApplicationRecord
belongs_to :user
end
class RecipeSave < ApplicationRecord
belongs_to :recipe
belongs_to :user
end
class User < ApplicationRecord
has_many :recipes, :dependent => :destroy
has_many :recipe_saves, :dependent => :destroy
has_many :saved_recipes,
through: :recipe_saves,
source: :recipe        # NOTE: use `recipe` association in `RecipeSave` model
#       instead of `saved_recipes`
end
# >> User.first.saved_recipes
# Rails couldn't find a valid model for RecipeSafe association.

我们可以看看rails是如何看到has_many :recipe_saves关联的:

>> User.reflect_on_association(:recipe_saves)
=> #<ActiveRecord::Reflection::HasManyReflection:0x00007f728a1c4a90
@active_record=User(id: integer, name: string),
@class_name="RecipeSafe", # NOTE: rails expects this class to be defined 
@inverse_name=nil,
@klass=nil,
@name=:recipe_saves,
@options={},
@plural_name="recipe_saves",
@scope=nil>

RecipeSafe类名由:recipe_saves推断:

>> :recipe_saves.to_s.singularize.camelize
=> "RecipeSafe"
# NOTE: this inflection is incorrect
>> :recipe_saves.to_s.singularize
=> "recipe_safe"
>> ActiveSupport::Inflector.inflections
...
@singulars=
...
[/([^f])ves$/i, "\1fe"],  # <= this one did it.
...
>> :recipe_saves.to_s.sub(/([^f])ves$/i, "\1fe")
=> "recipe_safe"

要解决这个问题,添加一个新的屈折规则:

# config/initializers/inflections.rb
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.singular "saves", "save"
end
>> User.reflect_on_association(:recipe_saves).class_name
=> "RecipeSave"
>> User.first.recipe_saves
=> [#<RecipeSave:0x00007f44a8fa5048 id: 1, user_id: 1, recipe_id: 1>]
>> User.first.saved_recipes
=> [#<Recipe:0x00007f44ac2c3f38 id: 1, user_id: 1>]     

为了避免混淆变化,重命名RecipeSaverecipe_saves表:

# in migration
create_table :recipe_bookmarks do |t|
t.references :user,   null: false, foreign_key: true
t.references :recipe, null: false, foreign_key: true
end
class Recipe < ApplicationRecord
belongs_to :user
end
class RecipeBookmark < ApplicationRecord
belongs_to :recipe
belongs_to :user
end
class User < ApplicationRecord
has_many :recipes, :dependent => :destroy
has_many :recipe_bookmarks, :dependent => :destroy
has_many :bookmarked_recipes, through: :recipe_bookmarks, source: :recipe
end
# >> User.first.bookmarked_recipes

https://guides.rubyonrails.org/association_basics.html the-has-many-through-association

https://api.rubyonrails.org/classes/ActiveSupport/Inflector.html

最新更新