HiveBrain v1.2.0
Get Started
← Back to all entries
patternrubyrailsMinor

Rails method to match users according to language fluency level

Submitted by: @import:stackexchange-codereview··
0
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 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
end


controller

#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
end


Let me

Solution

This is a somewhat shorter more concise version of your code. Taking advantages of some or Rails's magic and conventions.

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
end


This takes advantage of the has_many :languages in your User model. Also uses the pluck method which returns an array of language_ids

current_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
end
current_user.languages.where.where("level > 4").pluck(:language_id)

Context

StackExchange Code Review Q#163309, answer score: 2

Revisions (0)

No revisions yet.