How to order by associated model count - ruby-on-rails

City model:
class City < ActiveRecord::Base
has_many :angels
def angel_count
angels.size
end
end
Angel model:
class Angel < ActiveRecord::Base
belongs_to :city, :counter_cache => true
attr_accessible :city_id
end
I able to access the angel_count method through the rails_admin list action, however it won't allow me to change the order direction like the other columns.

Looks like you are using counter_cache wrong way. Do you have angels_count column in cities table? If not, add the column and run migration. You should be able to sort by this column.

Related

Create Rails scope comparing fields on two tables

I have a number of associated tables in an application
class Listing < ActiveRecord::Base
belongs_to :house
belongs_to :multiple_listing_service
end
class House < ActiveRecord::Base
has_one :zip_code
has_one :primary_mls, through: :zip_code
end
I wanted to create a scope that produces all the Listings that are related to the Primary MLS for the associated House. Put another way, the scope should produce all the Listings where the multiple_listing_service_id = primary_mls.id for the associated house.
I've tried dozens of nested joins scopes, and none seem to work. At best they just return all the Listings, and normally they fail out.
Any ideas?
If I understand correctly, I'm not sure a pure scope would be the way to go. Assuming you have:
class MultipleListingService < ActiveRecord::Base
has_many :listings
has_many :zip_codes
end
I would go for something like:
class House < ActiveRecord::Base
...
def associated_listings
primary_mls.listings
end
end
Update 1
If your goal is to just get the primary listing then I would add an is_primary field to the Listing. This would be the most efficient. The alternative is a 3 table join which can work but is hard to optimize well:
class Listing < ActiveRecord::Base
...
scope :primary, -> { joins(:houses => [:zip_codes])
.where('zip_codes.multiple_listing_service_id = listings.multiple_listing_service_id') }

How to write active record query to details by using and

i have two tables
1)Properties :fields are id, name, propert_type,category_id
2)Admins : fields id, name,mobile,category_id
i want to write an active record to list all properties , where category_id in properties table and category_id in Admins table are equal, according to current_user_id
i am listing this property list by logging as admin.
model relation
class Category < ActiveRecord::Base
has_many :admins,dependent: :destroy
has_many :properties,dependent: :destroy
end
class Admin < ActiveRecord::Base
belongs_to :category
has_many :properties
end
class Property < ActiveRecord::Base
belongs_to :admin
belongs_to :category
end
i wrote active record like this , but i got error,
can anyone please suggest me a solution for this
#properties= Property.where('properties.category_id=?','admins.category_id=?').and('admins.id=?',current_user.specific.id)
With your assosciation,You can use a sub query for getting your result in one line
#properties = Property.where(category_id: Admin.select("category_id").where(id: current_user.id))
As per my understanding current_user is an Admin. So You can search by the category_id of current_user. If I'm right, try this
#properties = Property.where(category_id: current_user.category_id)

Caching for model in rails

product.rb
has_many :votes
vote.rb
belongs_to :product
Every time, i use sorting in my index controller:
index_controller.rb
def index
#products = Product.all.sort { |m| m.votes.count }
end
So, i think it would be good to cache votes count for each product (create additional column votesCount in products table)?
If yes, can i preform that using before_save and before_delete callbacks in vote.rb model?
Or what is the best practice method?
Give me some examples please.
I guess you are looking for counter_cache
The :counter_cache option can be used to make finding the number of belonging objects more efficient
Consider these models:
class Order < ActiveRecord::Base
belongs_to :customer, counter_cache: true
end
class Customer < ActiveRecord::Base
has_many :orders
end
With this declaration, Rails will keep the cache value up to date, and then return that value in response to the size method.
Although the :counter_cache option is specified on the model that includes the belongs_to declaration, the actual column must be added to the associated model. In the case above, you would need to add a column named orders_count to the Customer model

HABTM relationship, How to input multiple values for id?

I have a User model which has_many Portfolios, which has_many Assets which has_and_belongs_to_many AssetHistories.
Basically User 1 might have Google in their portfolio and User 2 might also have Google in their portfolio. Why populate the database with duplicate lines of stock price history for Google when I can have a many-to-many (HABTM) relationship. However what throws me off is what to put for asset_id in the AssetHistory model when it will be multiple values. I.e. it needs to reference both user 1 and user 2. User 1's Google might be asset.id 1 and User 2's Google might be asset.id 2. Therefore how do the entries in the AssetHistory model reference both the ids?
It seems pretty clear that asset_id can't be 2 values simultaneously but I can't wrap my head around this. Am I supposed to use a foreign_key and make Google the key? If so, I still have issues in my Asset model for what entry to put for Asset_History_id, because the asset Google, will have maybe 30 lines of stock price history. Each stock price history would be a different Asset_History_id.
Can someone help explain what I'm doing wrong?
Note that I am using after_save in my asset model to populate the asset price histories. I.e. when someone adds an Asset, it populates the asset_history, but it doesn't populate the asset_history_id field in the Asset model and it doesn't populate the asset_id in the AssetHistory model because I'm at a lost on what to do there.
My asset model has:
class Asset < ActiveRecord::Base
attr_accessible :asset_symbol, :shares, :cost, :date_purchased, :asset_history_id
belongs_to :portfolio
has_and_belongs_to_many :asset_histories
after_save populatepricehistory
private
def populatepricehistory
#uses an api to download price data as an array and imports it to AssetHistory...
#I expect something should go here to fill out the asset_history_id field in the Asset Model
#while simultaneously filling out the asset_id in the AssetHistory model
end
end
Asset History model
class AssetHistory < ActiveRecord::Base
attr_accessible :close, :date, :asset_id, :asset_symbol
has_and_belongs_to_many :assets
end
Migration for AssetHistoryAsset join table
class AssetHistoryAssetJoinTable < ActiveRecord::Migration
def up
create_table :asset_histories_assets, :id=> false do |t|
t.integer :asset_id
t.integer :asset_history_id
end
end
def down
drop_table :asset_histories_assets
end
end
My suggestion would be this:
class User < ActiveRecord::Base
has_many :assets, :through => :porfolios
has_many :porfolios
end
class Porfolio < ActiveRecord::Base
has_many :assets
has_many :users
end
class Asset < ActiveRecord::Base
has_many :users, :through => :portfolios
has_many :portfolios
has_and_belongs_to_many :asset_histories
end
By the way, do you really need a many-to-many relationship between Asset and AssetHistory? I would imagine each instance of AssetHistory to refer to only one Asset, probably by means of belongs_to :asset / has_one :asset_history.

Rails has_one not saving foreign key

I have the following tables
keyword
keyword_id - PK
description
status_id - FK
keyword_status
status_id - PK
description
Trying to model them in AR and when attempting to save in my test it's not saving the status ID in keyword. They are mapped as such:
class Keyword < ActiveRecord::Base
self.table_name = :keyword
self.primary_key = :KEYWORD_ID
attr_writer :description
attr_writer :keyword_status
has_one :keyword_status, foreign_key: :STATUS_ID
end
class KeywordStatus < ActiveRecord::Base
self.table_name = :keyword_status
self.primary_key = :STATUS_ID
end
and the code where it breaks (keyword status is populated by a fixture)
keyword = Keyword.new
keyword.description = "keyword#{n}"
keyword.keyword_status = KeywordStatus.first
keyword.save
When keyword.save is called i get cannot insert NULL into 'STATUS_ID' on table Keyword
NOTE: I cannot change any of the DDL
As dstarh said, the foreign key association is backwards. In your models you should only need:
class Keyword < ActiveRecord::Base
has_one :keyword_status
end
class KeywordStatus < ActiveRecord::Base
belongs_to :keyword, :foreign_key => "status_id"
end
For the association to work. Also, setting the KeywordStatus object up with a fixture before creating the associated object is a bit odd but will work if that is the behavior you need. Also, why not just use the foreign key keyword_id and let rails handle it for you?
Update if you want to use keyword_id instead of status_id as the foreign key:
the tables will be as such:
keyword
id - PK
description
keyword_status
id - PK
keyword_id - FK
description
And your models:
class Keyword < ActiveRecord::Base
has_one :keyword_status
end
class KeywordStatus < ActiveRecord::Base
belongs_to :keyword
end
Hope this helps!
Update 2: Given the tables cannot change the association has to be a bit backwards. I would recommend:
class Keyword < ActiveRecord::Base
belongs_to :keyword_status
end
class KeywordStatus < ActiveRecord::Base
has_many :keywords, :foreign_key => "status_id"
end
I used a has many as the association since from what has been said it looks like a keyword can share a status that another keyword has. This also means that you will have to do something like:
KeywordStatus.first.keywords = KeywordStatus.first.keywords.push(keyword)
KeywordStatus.save
instead of:
keyword.keyword_status = KeywordStatus.first
Which operates in the opposite direction than you want. As you can see this can get pretty confusing so if at all possible i would suggest writing a migration to change your tables (this can be done for tables that have existing data if that is the problem). Again I hope this helps!
You got the direction wrong. It should be keyword belongs_to status. The general rule is that the model that has the foreign key column belongs to the other model.

Resources