rails - append to activerecord results - ruby-on-rails

A user has many followers.
I have a method in my users model that looks like this
def user_profile
ret = Hash.new
ret[:id] = id
ret[:name] = name
ret[:username] = username
ret[:bio] = bio
ret[:email] = email
ret
end
I would like to include whether the current_user is following the user being returned or not. Obviously "following" is not a field in the database but I have a table that stores users and who they follow. How can I efficiently append to every user whether the current users followers includes them or not?
Maybe doing a map or going through each user result in my controller?

You need to create one to many association between your user model and following method. While generating following model add User:belongs_to after adding fields of following method.

I ended up making it work like this but I don't think it's the most efficient way.
Basically get all the people the current user is following and see if the users in the users array match the id and put a true for following.
following = Follower.where(user_id: current_user.id)
users = users.map do |user_record|
user_record.as_json.tap do |user|
user[:following] = following.any? {|follower| follower.connection_id == user_record.id}
end

Related

Calculate a user_liked column for posts if a user is logged in

I'm using Rails API 5.0 in a blog application where users can log in and 'like' posts and comments similar to Facebook. When a user is logged in the client passes a token in the header of every request. This way my controller can see which user is making the request to the API.
# app/controllers/posts_controller.rb
if request.headers['Authorization']
token_string = request.headers['Authorization']
current_user = User.where(token: token_string).take
end
My models are set up so that users can have many posts, comments and likes. Likes of post and comments are kept in separate comment_likes and post_likes tables.
When a user is logged in I want them to be able to see all the posts and comments they have already 'liked' when viewing a list of posts or comments. I store this in an optional user_liked column. Initially I did this using a raw SQL query in my controller index method.
# app/controllers/posts_controller.rb
#posts = Post.joins("LEFT OUTER JOIN
(SELECT * FROM post_likes
WHERE post_likes.user_id = #{current_user.id}) AS pl
ON posts.id = pl.post_id")
.select("posts.*,CASE WHEN pl.user_id IS NULL THEN 0 ELSE 1 END AS user_liked")
However as I continue to work on the application I find that I want the user_liked column in every controller method when a user is logged in. It seems like it would be better to put it in the model.
Since the model doesn't have access to controller data, how can I create a model attribute that is dependent on current_user?
Create a method on the model and call it from the controller and pass through the current user.
Ex:
#likes = Post.user_liked(current_user)
render json: #likes

Rails 4 - Finding related user

Task: Showing the profile of an employee straight away after his login.
Issue:
class WelcomeController < ApplicationController
def index
#employee = Employee.find_by_email(params[#current_user.email])
end
end
I tried to code in many ways to associate the email of the current user with his respective details from the employees table and the farthest that I could get was it:
I am sure that I am writing something wrong in this line inside the index thing, but I am researching and all things that I found and tried did not get the employee related to the current user.
Try with this code:
class WelcomeController < ApplicationController
def index
#employee = Employee.where(email: current_user.email).first
end
end
When using Devise, the current user is an instance variable, so you don't need to prefix it with #.
If you are going to have a lot of users, is a good practice to create an index in your database for the email column.
I like kjmagic13's answer. Use the
#current_user.id
It pulls all the info associated with the user from the database
Mori's answer is also good.
The following SQL line in your logs corresponds to the Employee.find_by_email call:
SELECT "employees".* FROM "employees" WHERE "employees"."email" IS NULL LIMIT 1
As Mori pointed out, this means you're finding the employee with a nil email, which means that params[#current_user.email] is nil. Since you have no parameters, there's no need to refer to the params hash regardless. You should refer just to the #current_user.email:
Employee.find_by_email #current_user.email
As Mori's answer states, you probably didn't intent do use #current_user.email as a hash key into params. I think you're trying to look up the employee record for the current user by email (not by an email submitted as a parameter), like so (also avoiding deprecated find_by_* helpers):
#employee = Employee.find_by(email: #current_user.email)
I don't think you want to try to do Employee.find(#current_user.id) - that's just going to look up the Employee whose id matches the current_user's id - unless Employee and User use the same table that's not going to be meaningful
Why not just find by the ID? find_by_* are old.
#employee = Employee.find(#current_user.id)

After Created in Ruby on Rails

In controller my code is
query = "insert into users (name, email,updated_at) values (#{name},#{email},now()) ON DUPLICATE KEY UPDATE updated_at=now()"
User.connection.execute(query)
and in model
after_create :change_updated_at
def change_updated_at
if !self.email.blank?
chk_user = User.find_by_id(self.email)
if !chk_user.blank? && chk_user.updated_at.blank?
chk_user.updated_at =Time.now
chk_user.save!
end
end
end
but it's not working please help
Your query should be replaced by something like this. This will provide the same functionality as using ON DUPLICATE KEY UPDATE
user = User.where("name = ? and email = ?", name, email)
if user.nil?
user = User.new
end
user.name = name
user.email = email
user.save
Since you want this function to run even if it is an update. You want to use the after_save callback http://apidock.com/rails/ActiveRecord/Callbacks/after_save
The after_create is called only on creation of brand new objects.
http://apidock.com/rails/ActiveRecord/Callbacks/after_create
List of all callbacks provided by active record are here
http://apidock.com/rails/ActiveRecord/Callbacks
Don't run your query directly, that's VERY un-rails like. Let rails generate the query for you.
By running it yourself, rails has no way of knowing that you've created the record, so the after_create filter isn't be called.
Change your code to something like :
User.create(name: name, email: email)
Then it'll run. Also, don't update the 'create_at' field yourself. If you use rails methods, it'll do this automatically for you as well :)
You need to get with params object input attributes.
So first of all you need new method, and then create method (if you use standart form helper for model):
def create
#user=User.new(params[:user])
#other code
end

Multiple forms of authentication for a single field

I currently have a rails project that looks to let customers authenticate their account in two separate ways. Either they can use a bar code that they have stored in the database, or they can use a phone number. I want to merge these two fields so that there will be one field that allows two sources of authentication. Here is my code for the two fields.
def User.authenticate(barcode)
if user = find_by_barcode(barcode)
user
end
end
def User.authenticate2(phone_number)
if user = find_by_phone_number(phone_number)
user
end
end
Any suggestions would be greatly appreciated.
I would suggest using this one for simplicity of code:
def User.authenticate(barcode_or_phone_number)
find_by_barcode(barcode_or_phone_number) || find_by_phone_number(barcode_or_phone_number)
end
However it might cause 2 sql to be queried. So you may consider this:
def User.authenticate(barcode_or_phone_number)
where("users.barcode = ? OR users.phone_number = ?", barcode_or_phone_number, barcode_or_phone_number).first
end

random loop with conditions in rails

I have a feature called "Browse" that allows users to browse through random profiles. When a user clicks on "browse" they are immediately taken to a users profile that they are NOT already friends with. What should my controller look like?
Right now I've got:
def browse
#users = User.all.offset(rand(current_user.matches.count))
#users.each do |user|
if !current_user.friends.include?(user)
#user = user
return
end
end
end
However that doesn't seem to be working. Any advice? I am admittedly bad with blocks, it seems!
You could try something like this
def browse
#user = (User.all - current_user.friends).sample
end
A better version would be
def browse
#user = User.where('id not in (?)', current_user.friends.map(&:id))
.offset(rand(current_user.matches.count)).limit(1)
end
Also, if you are too concerned about performance, instead of using the offset technique, better use the randumb gem to fetch the random record. It uses database specific functions for selecting random records, if available.
Add an extra method to your User, something like this:
def random_stranger
self.class.where(%Q{
id not in (
select friend_id
from friends
where user_id = ?
}, self.id).
order('random()').
limit(1).
first
end
Then in your controller:
def browse
#user = current_user.random_stranger
end
If your database doesn't know how to optimize that not in then you could replace it with a LEFT OUTER JOIN combined with WHERE friend_id is null.

Resources