Meta_search error with model associations - ruby-on-rails

I have these in my controller:
class AccountsController < ApplicationController
def index
#search = Account.search(params[:search])
#accounts = #search.order("id desc").includes(:chef).page(params[:pagina]).per(10)
end
end
My view:
<%= f.text_field :username_or_email_or_chef_name_contains %>
Works fine! But, when I search based on email, I got this error:
ActiveRecord::StatementInvalid in Accounts#index
Mysql2::Error: Column 'id' in order clause is ambiguous: SELECT `accounts`.`id` AS t0_r0, `accounts`.`chef_id` AS t0_r1,...
If I take off the .includes(:chef) of account controller, works fine.
QUESTION
Why this error? For performance reasons, I wouldn't like to remove the include from account controller.

The accounts table and chefs table each have an id column, so MySQL doesn't know which of those columns it should order by. Try specifying the table name in the order by clause:
#accounts = #search.order("accounts.id desc").includes(:chef).page(params[:pagina]).per(10)

Related

How do I count unread comments using "Unread" Ruby gem?

comments_helper.rb:
module CommentsHelper
def unread_comments_count
#comments_count = Comment.unread_by(user).count
end
end
In my ApplicationController, I defined user:
def user
#user = User.find_by(params[:user_id])
end
I could have used current_user, but the result I got (with that) is total number of comments in my database. So, I thought I should use user. But it didn't work.
view:
<%= unread_comments_count %>
However, the result is still total number of all the comments made on all the posts by all users. I can't actually figure out what I am doing wrong because I have carefully done everything right in my Models as guided by the gem.
I would appreciate any clue to fix this.
Update
The query it generates is:
SELECT COUNT(*) FROM "comments" 'LEFT JOIN read_marks ON read_marks.readable_type = "Message" AND read_marks.readable_id = comments.id AND read_marks.reader_id = 1 AND read_marks.reader_type = 'User' AND read_marks.timestamp >= comments.created_at WHERE read_marks.id IS NULL

Passing Ruby SQL View parameters

I have a lot of data that I need to query out of a database. Heroku is timing out when I do the following, because of the 30 second limit:
account.records.all.each do |record|
record.contacts.all.each do |contact|
contact.address.all.each do |address|
..write to file etc
end
end
end
I've read that an SQL View will help with performance rather than querying every record in a .each(), however I need to do a where clause on this set of data. Currently, if I use the 'ExportAllRecord' view like so: ExportAllRecords.where("account_id = 3"), it executes the following:
ExportAllRecord Load (5.0ms) SELECT "export_all_records".* FROM "export_all_records" WHERE (account_id = 3)
whereas, I actually need it to add the 'where clause' to the view.
How can I parameterise the SQL View?
I'm using ActiveRecord.
Thanks.
ActiveRecord doesn't care where it queries from a normal database table or a database view.
Assuming your database view is named export_all_records, then just create a new model:
# in app/model/export_all_record.rb
class ExportAllRecord < ActiveRecord::Base
default_scope { readonly }
end
Use this model like a normal ActiveRecord model:
id = 3 # or perhaps params[:id]
ExportAllRecord.find_by(account_id: id)
#=> returns all records from the view with the given id
You can add more conditions if you need to:
ExportAllRecord.
where(account_id: id).
where(column1: true, column2: 'foobar')
order(:column3)

RoR Filter Out Current User with Join, Select and Order

I have the following statement in an RoR controller called nominations:
#users = User.joins(:department).select("CONCAT(last_name, ', ', first_name,
' - ', name) as user_dept, last_name, first_name, name,
users.id").order("last_name, first_name, middle_name")
In the view, I have this to put this in a drop down:
<%= select_tag "nomination[user_id]", options_from_collection_for_select(#users,
:id, :user_dept), prompt: "Select User" %>
I want to filter out the current user so that someone can't nominate themselves. I've seen several articles about using where.not or scope (for example) but all of the statements I could find are basic selections from one table. How do I define and use a scope while preserving all of the other stuff? I need that join and formatting.
Edit - Whenever I try where.not anywhere in the controller or model, I get the error "wrong number of arguments (0 for 1)".
This should do the trick:
#users = ...
#users = #users.where.not(users: {id: current_user.id})
Note that you need to specify name of the table (not the model) when you do the join, otherwise database will have no idea which id column it should look for (users.id vs departments.id).
Before Rails 4
not method is quite a new thing and is not available in Rails 3. (In fact, where method wasn't expecting to be called without arguments, that's why the error you got is unexpected number of arguments (0 for 1)).
Those were dark times when we had to use the following monstrosity to get stuff working:
#users = ...
#users = #users.where('users.id != ?', current_user.id)
You need a scope in the User model:
class User < ActiveRecord::Base
scope :except_id, -> (id) ( where.not(id: id) )
end
Then you can freely use it everywhere you want:
#users = User.except_id(current_user.id).joins(:department).select("...")
#users = User.where.not(id: current_user.id).joins(:department)
.select("CONCAT(last_name, ', ', first_name, ' - ', name) as user_dept, last_name, first_name, name, users.id")
.order("last_name, first_name, middle_name")

Why does ActiveRecord query return ambiguous column reference?

In a Rails app I'm setting up nested routes
resource Country do
resource State
resource City
resource User
resource Post
end
I now want to display users that have posted within a country at ../country/1/users
In the User controller I have:
def index
#user = User.includes(:posts, :city, :state, :country)
#user = #users.where("states.country_id = ?", params[:country_id]) if params[:country_id]
#active_users = #users.where('posts_count > ?', 0).ranked_scope
end
I'm, getting:
PG::Error: ERROR: column reference "posts_count" is ambiguous
LINE 1: ...untry_id" WHERE (states.country_id = '1') AND (posts_co...
I'm not sure if this is because:
There is a posts_count column on User, City, State, Country models and the query does not know which on to use. If so, what is the correct syntax to specify the table?
I'm stringing together two where clauses incorrectly.
Something else....?
I'd appreciate any suggestions or ideas.
Try:
#active_users = #users.where('users.posts_count > ?', 0).ranked_scope
OK, I eventually got to the bottom of this. The following query was incorrect
#users = #users.where("states.country_id = ?", params[:country_id]) if params[:country_id]
Post belongs to User, and Post has one Country through State. Without a direct relationship in one direction between USer and Country, I modified the query to
#users = #users.where(id: Country.find(params[:country_id]).users.uniq if params[:country_id]
(and double checked all my model relationships were properly configured).
Works!
The error message was not very helpful in tracking this down though!

ActiveRecord and SELECT AS SQL statements

I am developing in Rails an app where I would like to rank a list of users based on their current points. The table looks like this: user_id:string, points:integer.
Since I can't figure out how to do this "The Rails Way", I've written the following SQL code:
self.find_by_sql ['SELECT t1.user_id, t1.points, COUNT(t2.points) as user_rank FROM registrations as t1, registrations as t2 WHERE t1.points <= t2.points OR (t1.points = t2.points AND t1.user_id = t2.user_id) GROUP BY t1.user_id, t1.points ORDER BY t1.points DESC, t1.user_id DESC']
The thing is this: the only way to access the aliased column "user_rank" is by doing ranking[0].user_rank, which brinks me lots of headaches if I wanted to easily display the resulting table.
Is there a better option?
how about:
#ranked_users = User.all :order => 'users.points'
then in your view you can say
<% #ranked_users.each_with_index do |user, index| %>
<%= "User ##{index}, #{user.name} with #{user.points} points %>
<% end %>
if for some reason you need to keep that numeric index in the database, you'll need to add an after_save callback to update the full list of users whenever the # of points anyone has changes. You might look into using the acts_as_list plugin to help out with that, or that might be total overkill.
Try adding user_rank to your model.
class User < ActiveRecord::Base
def rank
#determine rank based on self.points (switch statement returning a rank name?)
end
end
Then you can access it with #user.rank.
What if you did:
SELECT t1.user_id, COUNT(t1.points)
FROM registrations t1
GROUP BY t1.user_id
ORDER BY COUNT(t1.points) DESC
If you want to get all rails-y, then do
cool_users = self.find_by_sql ['(sql above)']
cool_users.each do |cool_user|
puts "#{cool_user[0]} scores #{cool_user[1]}"
end

Resources