distinct for sorting with ransack - ruby-on-rails

i was trying to sort values of a table with sort_link from Ransack. i found an example which is really helpful. but, i think i'm having problem with 'distinct'. i got this error 'ORDER-BY expressions must appear in SELECT list; DISTINCT'.
my code looks like this :
q =user.joins(:buyer).order('users.name')
ransack = params["filter"]
#search = q.search(ransack)
#users = #search.result(:distinct=>true)
do i forget something? thanks in advance!

As per this issue you might be able to solve this with an ActiveRecord joins query or select query to add the columns needed, for example:
q = user.order('users.name')
ransack = params["filter"]
#search = q.search(ransack).
result(:distinct=>true).
joins(:buyer).
includes(:buyer)
#users = #search.all

You have distinct as true. Ransack called the distinct value in the wrong manner with Postgresql, thefore you getting this error. If you use another database, you mostlikely would not.
So, if you make distinct false, you will not get this error. If you want to know why you need distinct, check out:
http://www.w3schools.com/sql/sql_distinct.asp
I am trying to find a way to include distinct if I need it. when I find out, I will edit this answer.

Related

Combining queries into an ActiveRecord_AssociationRelation

Hi I'm working on a project and I need to take result of two database queries and combine them into one ActiveRecord_AssociationRelation, at the moment I have:
results.where(pos_or_neg: "neg").order("value DESC") + (results.where(pos_or_neg: "pos").order("value ASC"))
However this returns an array which doesn't work as I need to do more processing afterwards. I've tried:
results.where(pos_or_neg: "neg").order("value DESC").merge(results.where(pos_or_neg: "pos").order("value ASC"))
but this only seems to return the half of the results.
Thanks
results.order("pos_or_neg ASC,case when pos_or_neg="neg" then value else -1*value end DESC")
I believe using merge is the equivalent of an AND query in SQL. What you are looking for is an OR query.
Since Rails 5 this is one of the Active Record query methods that you can use!
http://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html#method-i-or
Try to replace your .merge with .or and see if that works better

How to use Arel::Nodes::TableAlias in an initial where statement

I got stuck on this and for sure it's easy, but I just cannot find the solution in the docs.
I have some tree structure and the child where clause that I have to filter with an "exists" sub query:
current_node.children.as("children_nodes").where(Node.where(...).exists)
The Node.where.clause already joins to the children_nodes and it works if I use two different models. But how do I use the alias? Above code will result in:
NoMethodError (undefined method `where' for #<Arel::Nodes::TableAlias
It's so basic, but something I'm missing (I'm too new to arel).
You might be able to use the attribute table_alias which you can call on an Arel::Table.
Example:
# works
users = User.arel_table
some_other_table = Post.arel_table
users.table_alias = 'people'
users.join(some_other_table)
# doesn't work
users = User.arel_table.alias('people')
some_other_table = Post.arel_table
users.join(some_other_table)
the as method generate an arel object which doesn't has where method such Relation object
the Arel object generates a sql to be executed basically its a select manager
you can use union and give it another condition then use to_sql
for example:
arel_obj = current_node.children.as("children_nodes").Union(Node.where(....)
sql_string = arel_obj.to_sql
Node.find_by_sql(sql_string)
here is some links that might help
http://www.rubydoc.info/github/rails/arel/Arel/SelectManager
In Arel, as will take everything up to that point and use it to create a named subquery that you can put into a FROM clause. For example, current_node.children.as("children_nodes").to_sql will print something like this:
(SELECT nodes.* FROM nodes WHERE nodes.parent_id = 5) AS children_nodes
But it sounds like what you really want is to give a SQL alias to the nodes table. Technically you can do that with from:
current_node.children.from("nodes AS children_nodes").to_sql
But if you do that, lots of other things are going to break, because the rest of the query is still trying to SELECT nodes.* and filter WHERE nodes.parent_id = 5.
So I think a better option is to avoid using an alias, or write your query with find_by_sql:
Node.find_by_sql <<-EOQ
SELECT n.*
FROM nodes n
WHERE n.parent_id = 5
AND EXISTS (SELECT 1
FROM nodes n2
WHERE ....)
EOQ
Perhaps you could also make things work by aliasing the inner table instead:
current_node.children.where(
Node.from("nodes n").where("...").select("1").exists
)

Subtracting two queries from each other in rails

I'm new to rails, and even ruby, so I'm having some trouble figuring this out.
I want to find the difference between two queries. This particular query should return a single record, since I've set it up such that Recipe is missing one of the IDs from recipes.
Current code:
q = Recipe.all - Recipe.where(recipe_id: recipes)
Where recipes is an array of IDs.
From my limited understanding of the language, this would work if both Recipe.all and Recipe.where both returned arrays.
I've spent some time searching the web, with nothing coming up to aid me.
Other things I've tried:
q = [Recipe.all] - [Recipe.where(recipe_id: recipes)]
q = Recipe.where.not(recipe_id: recipes) # Wouldn't work because the array is the one with the extra id
Though neither proved helpful.
Try this:
q = Recipe.where('recipe_id NOT IN (?)', recipes)
Turns out I was asking the wrong question.
Since the array of IDs is the one with extra elements, not the database query, I should have been comparing the difference of it to the query.
My answer is as follows:
q = recipes - Recipe.where(recipe_id: recipes).ids
Which returns the missing IDs.
If you are using Rails 4, you can use the not query method
q = Recipe.where.not(id: recipes)
this will generator following query:
SELECT "recipes".* FROM "recipes" WHERE ("recipes"."id" NOT IN (12, 8, 11, 5, 6, 7))

Rails 4, raw query using ActiveRecord

Is there currently a way to do a raw SQL select query using ActiveRecord in Rails 4.0.0.beta1? I see ActiveRecord::Base.execute no longer exists. What's the correct way of going about this?
Here try this, select example.. :
query = "select ...."
results = ActiveRecord::Base.connection.execute(query)
Just to add my ten pence, a raw query using Model.connection.execute won't return an ActiveRecord model - it'll return a raw data set.
The following will return ActiveRecord models:
MyModel.find_by_sql(query)
edit: assuming of course that you're running a select.
In Rails 4 (perhaps previous versions as well), if you're going with a custom query for speed, you can add a :skip_logging argument to avoid writing to the log:
query = "SELECT ..."
results = MyModel.connection.execute(query, :skip_logging)
(Note: If I'm reading the sources correctly, this might not hold true in PostgreSQL.)

Modifying the returned value of find_by_sql

So I am pulling my hair over this issue / gotcha. Basically I used find_by_sql to fetch data from my database. I did this because the query has lots of columns and table joins and I think using ActiveRecord and associations will slow it down.
I managed to pull the data and now I wanted to modify returned values. I did this by looping through the result ,for example.
a = Project.find_by_sql("SELECT mycolumn, mycolumn2 FROM my_table").each do |project|
project['mycolumn'] = project['mycolumn'].split('_').first
end
What I found out is that project['mycolumn'] was not changed at all.
So my question:
Does find_by_sql return an array Hashes?
Is it possible to modify the value of one of the attributes of hash as stated above?
Here is the code : http://pastie.org/4213454 . If you can have a look at summarize_roles2() that's where the action is taking place.
Thank you. Im using Rails 2.1.1 and Ruby 1.8. I can't really upgrade because of legacy codes.
Just change the method above to access the values, print value of project and you can clearly check the object property.
The results will be returned as an array with columns requested encapsulated as attributes of the model you call this method from.If you call Product.find_by_sql then the results will be returned in a Product object with the attributes you specified in the SQL query.
If you call a complicated SQL query which spans multiple tables the columns specified by the SELECT will be attributes of the model, whether or not they are columns of the corresponding table.
Post.find_by_sql "SELECT p.title, c.author FROM posts p, comments c WHERE p.id = c.post_id"
> [#<Post:0x36bff9c #attributes={"title"=>"Ruby Meetup", "first_name"=>"Quentin"}>, ...]
Source: http://api.rubyonrails.org/v2.3.8/
Have you tried
a = Project.find_by_sql("SELECT mycolumn, mycolumn2 FROM my_table").each do |project|
project['mycolumn'] = project['mycolumn'].split('_').first
project.save
end

Resources