Search in child model in Ruby on Rails - ruby-on-rails

A company model has many tag and has a country_id field. I would like to find:
all companies, located in a certain county
all companies, located in a certain county and has a certain tag if params[:tag] is present.
The first query is pretty easy
Company.where(:country_id => params[:country_id])
As for second one, I tried some queries and nothing worked
companies = Company.where(:country_id => params[:country_id])
companies = Company.tags.where(:name=> params[:tag])
undefined method `tags' for #<Class:0x000000055dfb60>
If I put
Company.tags.where(:name=> params[:tag])
then the error is the same
undefined method `tags' for #<Class:0x000000055dfb60>
In Rails console a command Company.first.tags receives all tags as it does.
UPDATE: this works
Company.joins(:tags).where("tags.name = ?", query_hash[:tag])
But I don't understand yet how to do something like this
my_conditions = get_search_conditions
if query_hash[:tag].present?
companies = Company.all(:conditions => my_conditions).joins(:tags).where("tags.name = ?", query_hash[:tag])
else
companies = Company.all(:conditions => conditions)
end
The error is
undefined method `all' for #<Array:0x007fbec8063e00>

The error is undefined method all for #<Array:0x007fbec8063e00>
It should work if you replace Company.all with Company.where

check if this works - Company.joins(:tags).where("tags.name",params[:tag])

Related

Some Instance Methods Are Undefined in acts_as_taggable

I am currently getting the following error on my post model which is under act_as_taggable_on for tags and channels.
undefined local variable or method `tag_list_on' for #
<ActiveRecord::Relation:0x007f9864675b48>
I seems that rails cannot detect the existence of tag_list_on or set_tag_list_on methods; however, it does detect the tagged_with method, whose source is located in the exact same module as the other files.
RubyMine can detect the existence of all of these methods fine btw.
Here is the section of code that I'm performing all of these operations on.
#posts = Post.tagged_with(params[:tags]).paginate(:page => params[:page]|| 1, :per_page => 20)
user_tags = #posts.tag_list_on(:tags)
custom_tags = user_tags - params[:tags]
#posts.set_tag_list_on(:customs, custom_tags)
#tags = #posts.tag_counts_on(:customs, :order => "count desc").limit(10)
#channels = #posts.tag_counts_on(:channels, :order => "count desc")
tagged_with is a class method of Post, added by the acts_as_taggable_on gem.
#posts in your code is an instance of ActiveRecord::Relation, not the Post class itself or any instance of it.
There is no tag_list_on instance method in ActiveRecord::Relation, hence the error.
tagged_with says it returns
...a scope of objects that are tagged with the specified tags.
tag_list_on and set_tag_list_on are instance methods of the Post class, added by the acts_as_taggable gem.
You need to call tag_list_on and set_tag_list_on for each instance of #posts
user_tags = []
#posts.each do |post|
user_tags = user_tags + post.tag_list_on(:tags)
end
custom_tags = user_tags.uniq - params[:tags]
# ...

How can this be re-written as an ActiveRecord query? (Rails)

I have the following method in a controller:
# GET /units/1
def show
#unit = Unit.find(params[:id]
#product_instances = Array.new
current_user.product_instances.each do |product_instance|
if product_instance.product.unit == #unit
#product_instances.push(product_instance)
end
end
... #rest of method
end
As can be seen, I have four tables/models: User, Product, ProductInstance, and Unit. A User has many ProductInstances. Each ProductInstance maps to a Product. A Unit has many Products.
I would like to fetch only the User's ProductInstances that are linked to a Product in the current Unit. The current code does it, but how can I re-write it better? I'd like to get rid of the for-each loop and if statement and replace it with chained ActiveRecord queries, if possible.
I tried something like below but it didn't work:
#product_instances = current_user.product_instances.where(:product.unit => #unit)
Seems you cannot do :product.unit.
I think you can try this
current_user.product_instances.joins(:product).where("products.unit_id = ?",#unit.id)
or with hashes
current_user.product_instances.joins(:product).where(:products => {:unit_id => #unit.id})

Rails3 nomethod error #<ActiveRecord::Relation>

I'm writing a static page controller.
I get the menuname in the routes.rb and it's call the static controller show method.
match '/:menuname' => 'static#show'
And static_controller.rb:
#static=Staticpage.where("menuname =
?", params[:menuname])
But if I want print #static.title in the view, I get this error:
undefined method `title' for #
Whats wrong?
the SQL query looks good:
SELECT staticpages.* FROM staticpages WHERE (menuname = 'asd')
Couple of working alternatives:
#static = Staticpage.where("menuname = ?", params[:menuname]).first
#static = Staticpage.find_by_menuname(params[:menuname])

Rails doing a FIND with Conditions?

In Rails 3, I created a Search Form that does a FIND with conditions in the Models file.
#projects = find(:all,
:select => 'projects.*',
:conditions => ['name = ?', search_name]
).first
This works great if a name is provided in the searchform (search_name). Problem is if search_name is blank, Rails Errors (can't say I blame it)...
What is the smart way to handle this situation? I'd like, if search_name is blank, to not error but return everything.
Suggestions? Thanks!
You can create a scope to handle this. In your Project model, add something like:
scope :search_by(name), lambda{|name| first.where(:name => name) unless name.blank?}
then in your controller, simply call:
Project.search_by(params[:search])
EDIT:
If you need to serach for multiple fields you can adapt the scope:
scope :search_by(name), lambda{|name| first.includes(:owner).where("projects.name LIKE ? OR owners.name LIKE ?", name, name) unless name.blank?}
if search_name.blank?
#projects = Project.order(:name)
else
#projects = Project.where(:name => search_name)
end
The cleanest way is using lazy loading with the new ActiveRecord functionalities like this:
#projects = Project.order(:name)
#projects = #projects.where(:name => search_name) if search_name
You can add as many conditions as you like this way. They won't be executed until you need the results anyway (with #projects.all or #projects.each, etc...)

Is it possible to filter by conditions before paginating?

I'm using ruby on rails 2.3.8 and will_paginate plugin.
I've just noticed that if I write something like this:
Announcement.paginate :page => params[:page], :per_page => 10, :conditions => some_condition
it will work.
But, if I write something like this:
announcements = Announcement.all :conditions => some_condition
#ann = announcements.paginate :page => params[:page], :per_page => 10
it won't recognize conditions.
EDIT:
I've developed a Search functionality and, due to a Sort functionality I had to implement, I had to put the search feat inside a model's method to call it from the controller every time I need either to search or sort by some field.
So, my model's methods look like this:
def self.search_by_relevance(words)
conditions = get_search_conditions(words)
Announcement.published.descend_by_featured.order_by_rate :conditions => conditions
end
where "published" and "order_by_rate" are named scopes and "descend_by_feature" belongs to "searchlogic" gem.
def self.get_search_conditions(words)
unless words.empty? or words.nil?
conditions = ''
words.each do |word|
if conditions.nil? or conditions.empty?
conditions = '(title like "%' + word + '%" or description like "%' + word + '%")'
else
conditions += ' and (title like "%' + word + '%" or description like "%' + word + '%")'
end
end
conditions
end
end
My controller's action looks like this:
def search
#announcements = Announcement.search_by_relevance(params[:txtSearch].to_s.split).paginate :page => params[:page], :per_page => 10 unless params[:txtSearch].nil? or params[:txtSearch].empty?
end
This syntax won't recognize the conditions specified in the model's method.
EDIT 2:
Thanks for the posts. Testing my code a little more I found out that if I write ".all" right after "order_by_rate" at this line Announcement.published.descend_by_featured.order_by_rate :conditions => conditions, in search_by_relevance method it will return the correct query, but will_paginate plugin will give me the following error(just if I add ".all"):
NoMethodError in AnnouncementsController#search
undefined method `to_i' for {:page=>nil, :per_page=>10}:Hash
D:/Proyectos/Cursometro/www/vendor/plugins/will_paginate/lib/will_paginate/collection.rb:15:in `initialize'
D:/Proyectos/Cursometro/www/vendor/plugins/will_paginate/lib/will_paginate/core_ext.rb:37:in `new'
D:/Proyectos/Cursometro/www/vendor/plugins/will_paginate/lib/will_paginate/core_ext.rb:37:in `paginate'
D:/Proyectos/Cursometro/www/app/controllers/announcements_controller.rb:276:in `search'
First of all, I don't understand why I have to add the ".all" to the query to work right, and second, I don't see why will_paginate won't work when I include ".all"(I also tried to add the following code but didn't work: :page => params[:page] || 1).
Also, if I include the ".all" syntax to the query, it will return:
SELECT * FROM announcements WHERE
((title like "%anuncio%" or
description like "%anuncio%")) AND
(announcements.state = 'published')
ORDER BY announcements.featured DESC
If I don't, it will return:
SELECT * FROM announcements WHERE
(announcements.state = 'published')
ORDER BY announcements.featured DESC
Do you see that no conditions are being included in the last one? This is causing the problem.
I don't know if this will work for you, but you can use paginate just like find, I mean, something like:
#announcements = Announcement.paginate_all_by_id params[:id],
:page => params[:page], :per_page => 10
Edit
#announcements is an array, right?
Well, I found this post and this other one that may help you.
Well, I kind of solve this by adding ".paginate"(instead of ".all") to my query in the model's method, passing by parameters the "page" and "per_page" values. It was not my idea to include pagination in models, but well...it's the solution I have for now. If you come up with a better one, I'll be glad to hear it :)

Resources