模型关联问题:NoMethodError:#<Hash...的未定义方法"扩展>



我目前正在按照升级指南将rails 5.2应用程序升级到rails 6.0。

一切似乎都很好,直到我的一个用户类(标签或艺术家(与链接模型交互时遇到错误。

当我试图以艺术家或标签的身份注册时,当我需要定义用户社交媒体或网站的链接时,我会收到以下错误:

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. 检查这个bug是否与我使用Discogs API的事实有关,以便在可能的情况下为新用户自动提取链接。但是,当我提到@label.links专门指向我的服务目录中的Discogs文件时,它把一切都搞砸了,因为它不再指向它应该指向的"链接"模型
  3. 在我的link.rb模型中添加belongs_to :label关联。不幸的是,它并没有改变任何事情

我在下面附上我的链接模型:

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

我的标签型号:

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模型中所述(时,答案总是肯定或为零。唯一会引发错误的问题是在检查@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错误。

对我来说,解决方案是在Rails6迁移期间将-> { uniq }更改为-> { distinct }

希望这能帮助到别人。

Koryto先生的答案看起来并不等价——当设置默认ORDER BY时,另一个默认WHERE。也许你应该试试

default_scope { order(ordered_links) }

解决方案毕竟很简单。轨道5.2和轨道6.0之间的范围界定部分似乎发生了变化。

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

在link.rb(我的链接模型(的第15行出现了一个问题,我在那里定义了范围:

default_scope { {order: ordered_links} }

对我有用的新语法如下:

default_scope { order(ordered_links) }

这些信息是从这里获取的。

最新更新