Is there a way to combine the following two queries (including the assignments) into one query? I'm not sure how much time I'd really save. In other words, I'm not sure if it is worth it, but I'd like to be as efficient as possible.
@contacts = @something.user.contacts.where.not(other_user_id: 0)
@user_contacts = @something.user.contacts.where(other_user_id: 0)
Here is my contacts table from schema.rb:
create_table "contacts", force: true do |t|
t.string "name"
t.string "email"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
t.string "profile_picture"
t.string "phone_number"
t.integer "other_user_id"
end
And here is the important stuff from the users table:
create_table "users", force: true do |t|
t.string "email"
t.datetime "created_at"
t.datetime "updated_at"
...
t.string "first_name"
t.string "second_name"
end
And here is the pertinent information of the models:
class Contact < ActiveRecord::Base
belongs_to :user
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i
validates :name, presence: true
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }
validates :user_id, presence: true
def get_email_from_name
self.email
end
end
[...]
class User < ActiveRecord::Base
has_many :contacts
has_many :relationships,
foreign_key: 'follower_id',
dependent: :destroy
has_many :reverse_relationships,
foreign_key: 'followed_id',
class_name: 'Relationship',
dependent: :destroy
has_many :commitments,
class_name: 'Commitment',
dependent: :destroy
has_many :followers,
through: :reverse_relationships
has_many :followed_users,
through: :relationships,
source: :followed
[...]
before_save { email.downcase! || email }
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i
validates :email,
presence: true,
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
[...]
def follow!(other_user)
relationships.create!(followed_id: other_user.id)
if create_contact?(self, id, other_user.id)
create_contact(other_user.name,
other_user.email,
self.id,
other_user.id,
other_user.gravatar_url)
elsif create_contact?(other_user, other_user.id, id)
create_contact(name, email, other_user.id, id, gravatar_url)
end
end
def create_contact?(user, followed_id, follower_id)
user.admin? && ! Relationship.where(followed_id: followed_id, follower_id: follower_id).empty?
end
def create_contact(name, email, user_id, other_user_id, profile_picture)
Contact.create!(name: name,
email: email,
user_id: user_id,
other_user_id: other_user_id,
profile_picture: profile_picture)
end
def unfollow!(other_user)
relationships.find_by(followed_id: other_user.id).destroy
Contact.destroy_all(user_id: self.id, other_user_id: other_user.id)
end
[...]
end
The other contacts that may not have an account with the website (yet), and I'd like to distinguish that in the view. So I keep track of which contacts I import through Google contacts using the omniauth
gem. For the other contacts, I gather the other users that are friends with current_user
.
I'd like to save these two record collections to use in the view, but I'd like to avoid looking through all the user's contacts twice, checking the same column in each pass-through.
Any ideas? I'm sure there are lots of ways this can be done, and I'd like to learn as much as I can from this! Thanks in advance!
You can use Array#partition
to split up the array in memory, after the query was performed.
@user_contacts, @contacts = @something.user.contacts.partition{|u| other.id == 0 }
However checking for this magic 0
id is smelly. You should try to get rid of such special cases whenever possible.