I'm currently upgrading my rails 5.2 app to rails 6.0 while following the upgrading guide.
Everything seems to work perfectly fine until I've encountered an error when one of my user classes (label or artist) interacts with the links model.
When I try to sign up either as an artist or as a label, I receive the following error when I get to the point where I need to define links to the user's social media or website:
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'
Here is my personal_informations_controller: (the error is at line 8 which I'll mark so it will be clear)
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
So far, I've tried 3 solutions:
belongs_to :label
association in my link.rb model. Unfortunately, it didn't change anything.I'm attaching my Link model below:
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
And my Label model:
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
It is important to mention that when I'm trying to write in the rails console to see if my current_label has any other property it should have as mentioned in my Label model, the answer is always either positive or nil. The only problem which raises an error is when checking for @label.links
For example:
>> @label.conversations
=> #<ActiveRecord::Associations::CollectionProxy []>
>> @label.name
=> "Test Label"
>> @label.links
!! #<NoMethodError: undefined method `extensions' for #<Hash:0x000000001001f1e8>
Did you mean? extend>
Thank you for assisting me!
I had a similar issue, and mine was this:
class Foo < ApplicationRecord
has_and_belongs_to_many :bars, -> { uniq }
end
When I call .bars
on a Foo, I got the undefined_method: extensions
error.
The solution for me was to change -> { uniq }
to -> { distinct }
during Rails 6 migration.
Hope this helps someone.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With