Model associations problem: NoMethodError: undefined method `extensions' for #<Hash...>

Model associations problem: NoMethodError: undefined method `extensions' for #<Hash...>

我目前正在将我的 rails 5.2 应用程序升级到 rails 6.0,同时遵循 upgrading guide.

在我的一位用户 类(唱片公司或艺术家)与链接模型交互时遇到错误之前,一切似乎都运行良好。

当我尝试注册为艺人或唱片公司时,当我需要定义指向用户社交媒体或网站的链接时收到以下错误消息:

Completed 500 Internal Server Error in 139ms (ActiveRecord: 7.3ms | Allocations: 14518)

    NoMethodError - undefined method `extensions' for #<Hash:0x000000000bdd4ec8>
    Did you mean?  extend:
      app/controllers/label/personal_informations_controller.rb:8:in `edit'

这是我的personal_informations_controller:(错误在第 8 行,我将标记出来以便清楚)

class Label::PersonalInformationsController < LabelController
  layout "signup"
  skip_before_action :ensure_approved

  def edit
    prepare_country_options
    @label = current_label
    @label.links.build(links_attributes) #***ERROR OCCURS HERE***#
  end

  def update
    @label = current_label
    if @label.update_attributes(label_params)
      redirect_to edit_label_genres_path
    else
      update_error
    end
  end

  private

  def update_error
    prepare_country_options
    @label.links.build(links_attributes)
    render :edit
  end

  def label_params
    params.require(:label).permit(:logo, :city, :country_code, :profile, links_attributes: [:id, :source, :url])
  end

  def prepare_country_options
    @country_options ||= Countries.prioritized.map { |country| [country.name, country.code] }
  end

  def links_attributes
    link_sources.map { |source| {source: source } }
  end

  def link_sources
    Link.sources - @label.links.map(&:source)
  end

end

到目前为止,我已经尝试了 3 种解决方案:

  1. 检查这个错误是否与默认自动加载器更改为 Zeitwerk 有任何关系,在检查了一段时间后我得出的结论是它与它没有任何关系。
  2. 检查此错误是否与我使用 Discogs API 的事实有关,以便在可能的情况下为新用户自动提取链接。但是,当我提到 @label.links 以专门指向我的服务目录中的 Discogs 文件时,它搞砸了一切,因为它不再指向它应该指向的 'Link' 模型。
  3. 在我的 link.rb 模型中添加 belongs_to :label 关联。不幸的是,它没有改变任何东西。

我在下面附上我的 Link 模型:

class Link < ApplicationRecord


  LINKS_ORDERED = ['website', 'facebook', 'twitter', 'youtube', 'soundcloud', 'lastfm']

  def self.ordered_links
    ret = "CASE"
    LINKS_ORDERED.each_with_index do |p, i|
      ret << " WHEN source = '#{p}' THEN #{i}"
    end
    ret << " END"
  end

  validates :url, presence: true
  default_scope { {order: ordered_links} }

  def self.website
    where(source: "website" )
  end

  def self.sources
    ["website", "facebook", "twitter", "youtube", "soundcloud", "lastfm"]
  end

  def self.icons
    ["globe", "facebook", "twitter", "youtube", "soundcloud", "lastfm"]
  end

  def to_partial_path
    "links/#{source}"
  end

  def account_name
    is_social_account? ? url.split("/").last : domain
  end

  def source
    read_attribute(:source) # guessed_source || ...
  end

  def icon
    self.class.icons[self.class.sources.index(source)]
  end

  def url=(url)
    url = "http://#{url}" unless url =~ /^https?\:\/\//
    write_attribute(:url, url)
  end

  private

  def is_social_account?
    (self.class.sources - ["website"]).include? source
  end

  def guessed_source
    self.class.sources.find { |source| url =~ /#{source}/ }
  end

  def domain
    url.gsub(/https?\:\/\//, "").split("/").first
  end

end

还有我的 Label 模型:

class Label < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable, :omniauthable
  include PgSearch::Model

  has_attached_file :logo, :s3_protocol => :https,
                    styles: { medium: "350x360#", thumb: "40x40#" },
                    default_url: ":class/:attachment/missing_:style.jpg"
  validates_attachment_content_type :logo, content_type: %r{\Aimage/.*\Z}
  alias_method :avatar, :logo

  has_and_belongs_to_many :genres
  has_many :feedback_requests
  has_many :payment_types, as: :payee
  has_many :links, as: :linkable, dependent: :destroy
  has_many :releases
  has_many :label_artists
  has_many :sent_messages, as: :from, class_name: "Message"
  has_many :messages, through: :conversations
  has_many :conversations
  has_many :songs, through: :feedback_requests, source: :song
  has_many :artist_contacts, through: :songs, source: :artist
  has_many :contracts, through: :conversations

  accepts_nested_attributes_for :payment_types
  accepts_nested_attributes_for :links, reject_if: ->(attributes) { attributes[:url].blank? }

  validates :name, :real_name, presence: true
  validates :city, :country_code, :profile, presence: true, on: :update

  delegate :name, to: :country, prefix: true, allow_nil: true

  pg_search_scope :search,
                  against: :name,
                  associated_against: { genres: :name },
                  using: {
                    tsearch: { dictionary: :english }
                  }

  pg_search_scope :by_relevance,
                  associated_against: { genres: :name },
                  using: {
                    tsearch: { dictionary: :english, any_word: true }
                  }

  def self.approved
    where("approved_at IS NOT NULL")
  end

  def approved?
    approved_at.present?
  end

  def payment_type
    payment_types.order("created_at").last
  end

  def display_name
    name
  end

  def country
    Country.new(code: country_code)
  end

  def location
    [city, country_name].compact.join(", ")
  end

  def logo_url(style = :medium)
    logo.url(style)
  end

  # The profit the label has earned (deducting Sendemo's cut)
  def balance_net
    ((raw_balance.to_i/100.0) * (1-Payment.sendemo_fee_fraction)).round(2) if raw_balance.present?
  end

  # A label's balance is the entire balance charged through the label including Sendemo's fee.
  # This is for backwards compatibility and should be changed
  def balance=(new_balance)
     write_attribute(:balance, (new_balance.to_f*100).to_i) if new_balance.present?
  end

  def balance
    (raw_balance.to_i/100.0).round(2) if raw_balance.present?
  end

  def raw_balance
    read_attribute(:balance)
  end

  def unread_messages_count
    messages.unread.count
  end

  def unread_messages?
    unread_messages_count > 0
  end
end

值得一提的是,当我尝试在 rails 控制台中写入以查看我的 current_label 是否有任何其他 属性 它应该如我在标签模型,答案总是肯定的或零。引发错误的唯一问题是在检查 @label.links

例如:

>> @label.conversations
=> #<ActiveRecord::Associations::CollectionProxy []>

>> @label.name
=> "Test Label"

>> @label.links
!! #<NoMethodError: undefined method `extensions' for #<Hash:0x000000001001f1e8>
Did you mean?  extend>

谢谢你的帮助!

我遇到了类似的问题,我的是这样的:

class Foo < ApplicationRecord
  has_and_belongs_to_many :bars, -> { uniq }
end

当我在 Foo 上调用 .bars 时,出现 undefined_method: extensions 错误。

我的解决方案是在 Rails 6 迁移期间将 -> { uniq } 更改为 -> { distinct }

希望这对某人有所帮助。

毕竟解决方案非常简单。 rails 5.2 和 rails 6.0 之间的范围部分似乎发生了变化。

Rails 5.2 仍然支持一种在 rails 3 中即将弃用的语法,而 rails 6.0 不再支持这种语法。

在 link.rb(我的 link 模型)第 15 行我定义范围时出现问题:

  default_scope { {order: ordered_links} }

对我有用的新语法如下:

  default_scope { order(ordered_links) }

信息取自here.

Koryto 先生的回答看起来并不相同 - 何时设置默认值 ORDER BY,另一个默认值 WHERE。也许你应该试试

default_scope { order(ordered_links) }