patternrubyrailsMinor
Rails method to match users according to language fluency level
Viewed 0 times
methodlevelmatchlanguagerailsfluencyusersaccording
Problem
This code works fine, but I'm still learning, and feel like there is a more Railsy way to write this. Is there a good rails ActiveRecord method I should learn more about? Please let me know if you know a shorter, more direct way to run this same code.
Scenario: A user can have many languages, and
user.rb
controller
Let me
Scenario: A user can have many languages, and
level is an attribute of languages. I want to iterate through languages_users and find all the languages of a user, and then find where another user has 2 of the same languages, but at opposite levels.user.rb
class User :languages_users
endcontroller
#Fluent languages and nonfluent languages can change depending on this situation, but here is good example:
@fluent_languages = LanguagesUser.where(user: current_user.id).where("level > 4")
@nonfluent_language = LanguagesUser.where(user: current_user.id).where("level < 5")
email_matches(@fluent_languages, @nonfluent_languages)
def email_matches(fluent_languages, nonfluent_languages)
@fluent_languages = fluent_languages
@nonfluent_languages = nonfluent_languages
#array of user's fluent language_ids
@fluent_langs = []
@fluent_langs << @fluent_languages
#array of user's nonfluent language_ids
@nonfluent_langs = []
@nonfluent_languages.each do |lang|
@nonfluent_langs << lang.language_id
end
@fluent_les = LanguagesUser.select(:user_id).where(language_id: @fluent_langs, level: 1..4)
@fluent_users_ids = []
@fluent_les.each do |le|
@fluent_users_ids << le.user_id
end
@nonfluent_les = LanguagesUser.select(:user_id).where(language_id: @nonfluent_langs, level: 5)
@nonfluent_user_ids = []
@nonfluent_les.each do |le|
@nonfluent_user_ids << le.user_id
end
@matches = @fluent_users_ids & @nonfluent_user_ids
@new_matches = User.where(id: @matches, status: "Active").order('last_seen DESC').limit(10)
@new_matches.each do |user|
UserMailer.new_match(user, current_user).deliver_later
end
endLet me
Solution
This is a somewhat shorter more concise version of your code. Taking advantages of some or Rails's magic and conventions.
This takes advantage of the
There is however a way to do this all in maybe 1-2 lines of SQL, maybe someone else will provide that magic here.
def email_matches(current_user)
fluent_ids = current_user.languages.where("level > 4").pluck(:language_id)
nonfluent_ids = current_user.languages.where("level < 5").pluck(:language_id)
fluent_user_ids = LanguagesUser.where(language_id: fluent_ids, level: 1..4)
.pluck(:user_id)
nonfluent_user_ids = LanguagesUser.where(language_id: nonfluent_ids, level: 5)
.pluck(:user_id)
matches = fluent_user_ids & nonfluent_user_ids
new_matches = User.where(id: matches, status: "Active").order(last_seen: :desc).limit(10)
new_matches.each do |user|
UserMailer.new_match(user, current_user).deliver_later
end
endThis takes advantage of the
has_many :languages in your User model. Also uses the pluck method which returns an array of language_idscurrent_user.languages.where.where("level > 4").pluck(:language_id)There is however a way to do this all in maybe 1-2 lines of SQL, maybe someone else will provide that magic here.
Code Snippets
def email_matches(current_user)
fluent_ids = current_user.languages.where("level > 4").pluck(:language_id)
nonfluent_ids = current_user.languages.where("level < 5").pluck(:language_id)
fluent_user_ids = LanguagesUser.where(language_id: fluent_ids, level: 1..4)
.pluck(:user_id)
nonfluent_user_ids = LanguagesUser.where(language_id: nonfluent_ids, level: 5)
.pluck(:user_id)
matches = fluent_user_ids & nonfluent_user_ids
new_matches = User.where(id: matches, status: "Active").order(last_seen: :desc).limit(10)
new_matches.each do |user|
UserMailer.new_match(user, current_user).deliver_later
end
endcurrent_user.languages.where.where("level > 4").pluck(:language_id)Context
StackExchange Code Review Q#163309, answer score: 2
Revisions (0)
No revisions yet.