rails/ruby: filtering - ruby-on-rails

query = Micropost.order("created_at desc")
unless params[:tag_id].blank? or params[:tag_id] == "Select a tag"
tags = Tag.all
params[:tag_id].each do |index|
query = tags[Integer(index) - 1].microposts.order("created_at desc") & query
end
end
This is the code I have. Basically tags have microposts and when I specify an array of tags from params[:tag_id] (I use a multiple select_tag), I want the intersection of all those microposts specified by the tags.
This code works when the array has only one tag but doesnt seem to work with more than 1. Wheres the bug?

I'm not sure if I fully understand what you are trying to do. But perhaps something along these lines is what you are after (goes inside the unless)?
For posts that have any tag:
tags = Tags.where(:id => params[:tag_id]).all
posts_with_tags = tags.map(&:microposts).flatten.uniq
For posts that have all tags:
tags = Tags.where(:id => params[:tag_id]).all
posts_with_tags = tags.map(&:microposts).inject { |memo, elem| memo & elem }

if you want the intersection of all Micropost with the collection of microposts associated with the tags selected you have only to query for all the micropost associated with the selected Tag and collect the microposts.
with rails3
unless params[:tag_id].blank? or params[:tag_id] == "Select a tag"
query= Tag.where(["id in (?)",params[:tag_id]]).collect(&:microposts).uniq
end
maybe i have misunderstood your question , sorry .

Related

Rails retuning an array of ids with multiple conditions

In my controller i'm looking to return an array with 2 conditions attached.
parent_ids = StudentGuardian.where(:guardian_id => current_user.school_user.id).pluck(:student_id)
classmodule_ids = SubjectStudent.pluck (:class_id)
#homework = Homework.where("subject in ?", classmodule_ids)
So in this case I need to find a student id from a table and then I need to get a class_id from another table.
Then I am trying to display results.
Can I get both in to the one query?
I also tried #homework = Homework.where("subject in ?", parent_ids, classmodule_ids)Of course this does not work!
You just want to know if subject is in parent_ids or classmodule_ids?
So can you just merge parent_ids and classmodule_ids into one array:
# you could merge these a bunch of different ways, here's one:
search_ids = (parent_ids + classmodule_ids).uniq
# don't forget the () around ? below
#homework = Homework.where("subject in (?)", search_ids)
Or if for some reason you didn't want to combine parent_ids and classmodule_ids:
#homework = Homework.where("subject in (?) OR subject in (?)", parent_ids, classmodule_ids)
But all of that would mean subject is an id also... Is that the case?

Filtering in Spree 3.1

I need product properties' filters on taxon's show page.
Heres's what i've added to my spree/taxon_controller.rb show method:
if params[:filter].present?
params[:filter].each do |k,v|
pp=#product_properties.where("property_id = ? and value in (?)", #properties.find_by(name: k), v).pluck(:id)
#products = #products.joins(:product_properties).where("spree_product_properties.id in (?)", pp)
end
end
I trying to do similiar query in console:
Spree::Product.joins(:product_properties).where("spree_product_properties.id in ?", [3,23]).where("spree_product_properties.id = ?", 4)
But it returned nothing.
If delete last where-statement, it's all ok
Spree::Product.joins(:product_properties).where("spree_product_properties.id in ?", [3,23])
One product object contain product_properties with id 3 and 4.
What i do wrong?
P.S. First i try to use spree's filter system with custom search as it write here, but it didn't work at all.
P.P.S I think filters is preetty stndart feature for e-shop, why it so many problems with them in spree?!

Sorting a Rails active record

I have a table A(:name, :address, :country_id). I run this query
ids = [1,2,3]
#result = A.where(country_id: ids)
But, I want to get the results in this order : records containing country_id = 2 first, then 1 and then 3.
How should I write this query?
Edit :
#people = []
#result.each do |r|
#people.push([r,r.name])
end
I have an array #people of arrays now and want to sort it. What should be the query now?
Another Edit :
#people.sort_by! {|p| preferred_order.index(p.first.country_id)}
This worked.
You can use sort_by :
ids = [1,2,3]
preferred_order = [2,1,3]
#result = A.where(country_id: ids)
#result.sort_by! { |u| preferred_order.index(u.country_id) }
One option would be adding an extra column
rails g migration add_sortorder_to_A sort_order:integer
Then add a
before_save :update_sort_order
def update_sort_order
if self.country_id == 1
self.update_attributes(sort_order:2)
elsif self.country_id ==2
self.update_attributes(sort_order:1)
........
end
Alternatively, put your sort_order in the countries and sort on that.
Alternatively, create a dynamic field which will give you the sort_order.
There is probably a more elegant way of doing this, but this should work in a quick and dirty way and allow you to use standard activerecord queries and sorting. (i.e. you can just forget about it once you've done it the once)

optimizing select query on has_many :through attributes association

I want to find all posts that are tagged with tags that are passed in a params array.
post has many tags through association.
currently my code looks like this:
if params.has_key?(:tags)
params[:tags].each do |tag|
#tags = Array.new if #tags.nil?
#tag = Tag.find_by_content(tag)
#tags << #tag if #tag
end
#allposts = Post.followed_by(#user).select { |p| p.tags.size != 0 && (p.tags & #tags).size == p.tags.size }
else
#allposts = Post.followed_by(#user)
end
what i'm basically doing is finding the actual tag models according to the params array and putting them into an array, then I run a select query on all posts searching for those with the same tags array.
is there a better and cleaner way to do this ?
You can roll your Tag.find query into a single request to the DB, and add an appropriate where clause to limit the posts returned:
finder = Post.followed_by(#user)
if params.has_key?(:tags)
#tags = Tag.where(:content => params[:tags])
finder = finder.with_tags(#tags)
end
#allposts = finder.all
in app/models/post.rb
scope :with_tags, lambda { |tags| joins(:tags).group('posts.id').where(:tags => { :id => tags.map { |t| t.id } } ).having("COUNT(*) = ?", tags.length) }
UPDATE
Here's what the with_tags scope does:
joins(:tags) Firstly we join the tags table to the posts table. Rails will do with with an inner join when you use the symbol syntax
where(:tags => { :id => tags.map { |t| t.id } } ) We want to filter the tags to only find those tags provided. Since we are providing a list of tag objects we use map to generate an array of IDs. This array is then used in the where clause to create a WHERE field IN (list) query - the hash within a hash syntax is used to denote the table, then column within the table.
group('posts.id') So now that we have a list of posts with the requisite tags, however, if there are multiple tags we will have posts listed multiple times (once for each matched tag), so we group by the posts.id so that we only have 1 row returned for each post (it's also required to that we can do the count in step 4)
having("count(*) = ?", tags.length) This is the final piece of the puzzle. Now that we've grouped by the post, we can count the number of matched tags associated with this post. So long as duplicate tags are not allowed then if the number of matched tags (count(*)) is the same as the number of tags we were searching with (tags.length) Then we can be sure that the post has all the tags we were searching with.
You can find a lot more information about the different query methods available for models by reading the Active Record Query Interface Guide

Rails: combining optional params into a query

I have a view with a huge paginated list of records that need filtering.
Users can filter by records a few different ways (such as 'saved' records, 'read' records, and 'mark deleted' records) and I'd like for them to be able to combine these filters any possible way.
My current, flawed, non-functioning approach. The code below does not produce anything unless all of the params are specified and valid:
#view. Set the 'se' filter to true; leave all others as is
<%= link_to list_url(:id=>params[:id], :se=>"true", :st=>params[:st], :re=>params[:re]) do %>
<div class="button">Toggle SE</div>
<% end %>
#controller query. Add whichever params are passed into the conditions for the new page.
#query is paginated and sorted
#records = Record.where("user_id IN (?) AND see = ? AND star = ? AND delete = ? AND like = ?", #users.select("id"), params[:se], params[:st], params[:re]).paginate :page => params[:page], :order => (sort_column + " " + sort_direction)
What is the best way to create this filtering system?
I imagine a client-side sort would be faster than asking the server to become involved every time - is there a simple AJAX way to accomplish this kind of thing? Imagine filters the user can toggle on and off in any combination.
Try this:
conditions = {:user_id => #users.select("id")}
{
:se => :see,
:st => :star,
:del => :delete
}.each{|k1, k2| conditions[k2] = params[k1] unless params[k1].blank?}
#records = Record.where(conditions).paginate(...)
The conditions hash will be filled based on the values present in the params hash.
Edit 1
You can combine conditions hash and array.
#records = Record.where(conditions).where(
":created_at > ?", Date.today - 30).paginate(...)
You can change the user_id condition to what ever you want by specifying
conditions[:user_id] = #user.id
In the above statement, if the RHS is an array, rails automatically generates the IN clause. Otherwise, equality check(=) is performed.
Can also use Anonymous scopes: Combine arrays of conditions in Rails

Resources