Rails: Get only certain attributes of submodel with method 'attributes' - ruby-on-rails

Is there a way to get only certain fields of a foreign model like this:
#user = User.find(:first, :select => ['`users`.`id`, `users`.`nickname`, `users`.`birthdate`, `users`.`sex`'], :conditions => ['`users`.`id` = ?', id])
city = #user.profile.city.attributes
With attributes I retrieve all attributes of my city model. I'd like to get only some. Something like:
city = #user.profile.city.attributes[:name, :postcode]
Is it possible by keeping the syntax as simple as above? I want to use attributes to receive a Hash.
thanks a lot.

You could do this if you don't mind that it picks out fields after the SQL returns everything:
#user.profile.city.attributes.select{|k,v| ["name","postcode"].include?(k)}

It's not possible to select fields of foreign models when chaining in the way you have. The only way would be to do a query on the City model:
City.where(:profile_id => #user.profile.id, :select => ...)

You cannot give arguements after attributes otherwise it will raise ArguementError. In this case you can use inner join to fetch the records.

city = #user.profile.city.pluck(:name, :postcode)

Related

Ruby on Rails: Fetch database result and search through results

I have a set of IDs for a table called "brands". I want to fetch the name column for each record in the brand table without having to re-query the database using Brand.find(brand_id). Instead, is there a way to store the database results into a variable and query the variable?
Thanks.
if you already collected the records in a var #brands, you can use
name = #brands.find {|b| b.id == brand_id}.name
not a query
This will return an array of all Brands for a brand_id
Brand.find(:all, :conditions => ["brand_id = ?", brand_id])
For a collection of brand_ids
Brand.find(:all, :conditions => ["brand_id IN (?)", [brand_id1, brand_id2]])
HTH
You can write a method in your model brand.
def get_associated_brand
b = self.brand_id
brand = Brand.find(b).name
end
From your view just call this method so that in your view you ll get brand name instead of ID like
brand.get_associated_brand
instead of
brand.brand_id
About what was commented on #Harsh Gupta's answers, maybe
#filtered_brands = Brand.where(id: <some_id>)
Then you can access all info of each brand in a regular each loop.

Rails search serialized records

In the model I serialize the column category in Event model to be array, so i have
serialize :category
The thing is, i need to provide search function to users. So how do i search if a category is inside an event.
Event.find(:all, :conditions => ['category = ?', params[:category]])
This won't work as the category is stored as serialized array. Any idea?
The only way i can think of get all the events and filter out each instance.
Event.all.select{|e| e.category.include? params[:category]}
This is not efficient at all.
Or else, i can use like statement
Event.find(:all, :conditions => ['category = ?', "%-#{params[:category]}%"])
I would create a separate table and model for categories. Then you can get all events in a category by using a has_many association.
You can use .to_yaml to match the serialize format stored in the DB.
Event.where(category: params[:category].to_yaml)
Event.where("category IN (?)" , params[:category].to_yaml)

Is it possible to delete_all with inner join conditions?

I need to delete a lot of records at once and I need to do so based on a condition in another model that is related by a "belongs_to" relationship. I know I can loop through each checking for the condition, but this takes forever with my large record set because for each "belongs_to" it makes a separate query.
Here is an example. I have a "Product" model that "belongs_to" an "Artist" and lets say that artist has a property "is_disabled".
If I want to delete all products that belong to disabled artists, I would like to be able to do something like:
Product.delete_all(:joins => :artist, :conditions => ["artists.is_disabled = ?", true])
Is this possible? I have done this directly in SQL before, but not sure if it is possible to do through rails.
The problem is that delete_all discards all the join information (and rightly so). What you want to do is capture that as an inner select.
If you're using Rails 3 you can create a scope that will give you what you want:
class Product < ActiveRecord::Base
scope :with_disabled_artist, lambda {
where("product_id IN (#{select("product_id").joins(:artist).where("artist.is_disabled = TRUE").to_sql})")
}
end
You query call then becomes
Product.with_disabled_artist.delete_all
You can also use the same query inline but that's not very elegant (or self-documenting):
Product.where("product_id IN (#{Product.select("product_id").joins(:artist).where("artist.is_disabled = TRUE").to_sql})").delete_all
In Rails 4 (I tested on 4.2) you can almost do how OP originally wanted
Application.joins(:vacancy).where(vacancies: {status: 'draft'}).delete_all
will give
DELETE FROM `applications` WHERE `applications`.`id` IN (SELECT id FROM (SELECT `applications`.`id` FROM `applications` INNER JOIN `vacancies` ON `vacancies`.`id` = `applications`.`vacancy_id` WHERE `vacancies`.`status` = 'draft') __active_record_temp)
If you are using Rails 2 you can't do the above. An alternative is to use a joins clause in a find method and call delete on each item.
TellerLocationWidget.find(:all, :joins => [:widget, :teller_location],
:conditions => {:widgets => {:alt_id => params['alt_id']},
:retailer_locations => {:id => #teller_location.id}}).each do |loc|
loc.delete
end

How to query a joined table (has_and_belongs_to_many) in a controller

I have established a relation between project.rb and keyword.rb using has_and_belongs_to_many.
I now want to query in my projects-controller all projects linked to a certain keyword. What is the easiest way to query the joined table keywords_projects?
Where is the connector from projects.rb to the joined table?
#projects = Project.find(:all, :conditions => [??])
Any help is much appreciated. Thx.
Easy way:
#projects = Keyword.find('keyword').projects
or:
#projects = Project.all(:conditions => {:keywords => {:name => 'keyword'}}, :include => :keywords)
Ok, it seems something's wrong in my Rails app then:
In both my models (here Folder and Role), I have habtm's defined (:roles, :folders). CRUD works, the folders_roles table exists so the DB is populated flawlessly. But when trying to query ...
#folders = Role.where("name = ?", "family").folders
... in my folder's controller, Rails barks about ...
undefined method `folders' for #<ActiveRecord::Relation:0xb6ecc12c>
(I simply want to load only those folders, that are associated with the role called "family".)

Targeting every object in an array syntax

Newb question of the day:
I'm trying to select all the users with this condition, and then perform an action with each one :
User.find(:all).select { |u| u.organizations.count > 0} do |user|
Except, this isn't the right way to do this. Not entirely sure what the proper syntax is.
Any fellow rubyist offer a newb a hand?
To perform an action with each element of a collection use the each method, like this:
User.find(:all).select { |u| u.organizations.count > 0}.each do |user|
You'd probably be better folding the select into the query with:
User.find(:all, :conditions => "organization_id IS NOT NULL").each do |user|
This will only fetch the relevant results from the database so there should be less unnecessary data retrieved and thrown away.
EDIT:
As suggested in the comments, the following would be correct for a many-to-many relationship assuming a join model called memberships (where user has_many :organisations, :through => :membership)...
User.all(:joins => "inner join memberships on memberships.user_id = users.id")

Resources