How are I18n and database ActiveRecord querying related? - mysql

Does anyone know, what does I18n have to do with database?
class DecorativeCentersSalesRepresentative < ActiveRecord::Base
belongs_to :decorative_center, class_name: ::DecorativeCenter
belongs_to :user, class_name: ::SalesRepresentative
end
class DecorativeCenter < ActiveRecord::Base
has_many :decorative_centers_sales_representative
has_many :sales_representatives,
through: :decorative_centers_sales_representative
end
class SalesRepresentative < User
has_many :decorative_centers_sales_representative,
foreign_key: :user_id
has_many :decorative_centers,
through: :decorative_centers_sales_representative,
foreign_key: :user_id
end
All is good, and I can do
SalesRepresentative.last.decorative_centers
SalesRepresentative Load (0.7ms) SELECT `users`.* FROM `users` WHERE `users`.`type` IN ('SalesRepresentative') ORDER BY `users`.`id` DESC LIMIT 1
DecorativeCenter Load (0.3ms) SELECT `decorative_centers`.* FROM `decorative_centers` INNER JOIN `decorative_centers_sales_representative` ON `decorative_centers`.`id` = `decorative_centers_sales_representative`.`decorative_center_id` WHERE `decorative_centers_sales_representative`.`user_id` = 4
#=> [#<DecorativeCenter:0x000000088e5578]
But when I do
DecorativeCenter.last.sales_representatives
DecorativeCenter Load (0.2ms) SELECT `decorative_centers`.* FROM `decorative_centers` ORDER BY `decorative_centers`.`id` DESC LIMIT 1
#=> I18n::InvalidLocale: :en is not a valid locale
#=> from /home/andreydeineko/.rvm/gems/ruby-2.3.0#profill-base/gems/i18n-0.7.0/lib/i18n.rb:284:in `enforce_available_locales!'
WHY??
I know it is an invalid locale, valid one is :pl:
I18n.available_locales
#=> [:pl]
I18n.default_locale
#=> :pl
But how are these things even related and why can I query one way, and can not other?

After some time of debugging I have found the real issue.
Starting from the end:
class HasManyThroughSourceAssociationNotFoundError < ActiveRecordError #:nodoc:
def initialize(reflection = nil)
if reflection
through_reflection = reflection.through_reflection
source_reflection_names = reflection.source_reflection_names
source_associations = reflection.through_reflection.klass._reflections.keys
super("Could not find the source association(s) #{source_reflection_names.collect(&:inspect).to_sentence(:two_words_connector => ' or ', :last_word_connector => ', or ', :locale => :en)} in model #{through_reflection.klass}. Try 'has_many #{reflection.name.inspect}, :through => #{through_reflection.name.inspect}, :source => <name>'. Is it one of #{source_associations.to_sentence(:two_words_connector => ' or ', :last_word_connector => ', or ', :locale => :en)}?")
else
super("Could not find the source association(s).")
end
end
end
In this error locales were hardcoded, and it is :en, that is why I could not even get the error message.
1) In my app :en was not within available locales, so in order to get the error message Rails was tying to spit out, I temporarily set the app's locale to :en.
2) Now I could get the error:
ActiveRecord::HasManyThroughSourceAssociationNotFoundError: Could not find the source association(s) "sales_representative" or :sales_representatives in model DecorativeCentersSalesRepresentatives. Try 'has_many :sales_representatives, :through => :decorative_centers_sales_representatives, :source => <name>'. Is it one of versions, decorative_center, or user?
Which simply states, that I was wrong in writing belongs_to in my join table.
AR expects the name of an association to be defined, not a table in database.
So changing
# (STI) table users, but AR model is called SalesRepresentative
belongs_to :user, class_name: ::SalesRepresentative
to
# changed to real AR table name passing the foreign_key
belongs_to :sales_representative, class_name: ::SalesRepresentative, foreign_key: :user_id
made it work as expected.

Related

Rails has many :through relationship causing stack level too deep

class User < ActiveRecord::Base
has_many :case_users
has_many :cases, :through => :case_users
end
class CaseUser < ActiveRecord::Base
belongs_to :case
belongs_to :user
end
class Case < ActiveRecord::Base
has_many :case_users
has_many :users, :through => :case_users
end
When I try to hit any users or cases endpoint, it continually sends queries to the DB like:
SELECT `cases`.* FROM `cases` INNER JOIN `case_users` ON `cases`.`id` = `case_users`.`case_id` WHERE `cases`.`deleted_at` IS NULL AND `case_users`.`deleted_at` IS NULL AND `case_users`.`user_id` = 1 [["user_id", 1]]
and like:
SELECT `users`.* FROM `users` INNER JOIN `case_users` ON `users`.`id` = `case_users`.`user_id` WHERE `users`.`deleted_at` IS NULL AND `case_users`.`deleted_at` IS NULL AND `case_users`.`case_id` = 1 [["case_id", 1]]
Why is this happening?
Edit:
These models are actually much larger (80-100 lines), but I've commented bits out and believe this is what's causing the problem/error. Also it's running these queries when crashing, which leads me to believe that it's coming from this relationship.
After spending ~1 hour looking at my models, my database schema, and testing all over, I found it was a problem in my serializer.
I had has_many :users in my serializer for cases, and that caused the error.

ruby on rails before_save increments different column of table

here is my like.rb model
class Like < ActiveRecord::Base
attr_accessible :user_id, :post_id
before_save :increment_post_total_likes
before_destroy :decrement_post_total_likes
scope :desc_ordered, :order => "created_at DESC"
belongs_to :post
belongs_to :user
def increment_post_total_likes
p = Post.find(self.post_id)
p.increment!(:total_likes)
p.save
end
def decrement_post_total_likes
p = Post.find(self.post_id)
p.decrement!(:total_likes)
p.save
end
def self.alreadyLiked(post_id, user_id)
where(:user_id => user_id, :post_id => post_id).any?
end
def self.already_liked?(user_id)
exists?(:user_id => user_id)
end
end
the problem is that when i like a post, it increments the post total_likes column but also increments the another table column which those 2 share associated columns like post_id and user_id and i don't get why...
I want to use before_save and before_destroy only on the likes table
increment! will save the record for you. Try it without the bang.

Rails 3: How to make a join in mysql over 3 tables (with :through in the model)

ingredient.rb:
class Ingredient < ActiveRecord::Base
has_many :recipes, :through => :ingredients_with_quantities
has_many :ingredients_with_quantities
ingredient_with_quantity.rb:
class IngredientWithQuantity < ActiveRecord::Base
belongs_to :recipe
belongs_to :ingredient
recipe.rb:
class Recipe < ActiveRecord::Base
has_many :ingredients, :through => :ingredients_with_quantities
has_many :ingredients_with_quantities
I would like to make a query which get all recipes that includes a specific ingredient name.
Tried this query:
Recipe.find(:all, :include => {:ingredients_with_quantities => :ingredients}, :conditions => "ingredients.name = 'ingredient1'")
But I get this error:
NameError: uninitialized constant Recipe::IngredientsWithQuantity
Can someone tell me whats wrong with the query?
I can make a successfull query in SQL with:
SELECT r . * FROM recipes r, ingredient_with_quantities iq, ingredients i
WHERE i.name = "ingredient1"
AND iq.recipe_id = r.id
AND iq.ingredient_id = i.id
How does this query looks in Rails with ActiveRecord?
Thanks for helping me out!!
It is :ingredient_with_quantities rather than :ingredients_with_quantities (you put a "s" after ingredient)

Rails Query for best way to select the most recent record

I have this method which I want me to fetch the most recent activity_id for the corresponding user_id from the model UserActivity that keeps track of all the user activities and from that get the description of the activity_id from another model Activity.
The function works fine but at times throws bugs as "Not able to find activity_id". May be there could be a better way to implement this or Am I doing something wrong here ?
def last_activity(date, user_id)
active_id = UserActivity.find(:all, :conditions => ["Date(updated_at) <= ? and user_id = ?", date, user_id]).last.activity_id
text = Activity.find(active_id).description
end
The Schema of the model UserActivity is as follows :
Please help me get this fixed. Thanks !!
Ruby version 1.8.7, Rails 2.1.2
Assuming you have following models
class User
has_many :user_actvities
has_many :activities, :through => :user_actvities,
:order => "user_actvities.id"
end
class UserActivity
belongs_to :user
belongs_to :activity
end
class Actvity
has_many :user_actvities
has_many :users, :through => :user_actvities
end
To get the current user's last activity
current_user.activities.last
This relies on the fact that UserActivity object with the max id is the latest activity.
If you update the UserActivity after creation, you have to change the order clause of the association, i.e.
has_many :activities, :through => :user_actvities,
:order => "user_actvities.updated_at"
Either the query is not finding any match or some records might be having null values for activity_id column, following code should work
user_activity = UserActivity.find(
:all, :conditions => ["DATE(updated_at) <= ? AND user_id = ? AND activity_id IS NOT NULL", date, user_id],
:order => "updated_at DESC", :limit => 1).first
text = Activity.find(user_activity.active_id).description rescue nil

rails: can't get the attributes from the joined table

When I join two tables (rails 2.2.2), then rails only returns the values of the attributes from the Model for which the find_by method is applied:
Relations:
class User < ActiveRecord::Base
..
has_one :company_info, :dependent => :destroy
has_many :preferred_categories, :dependent => :destroy
end
class PreferredCategory < ActiveRecord::Base
..
belongs_to :user
belongs_to :category
end
class Category < ActiveRecord::Base
..
has_many :preferred_categories, :dependent => :destroy
has_many :users, :through => :preferred_categories
end
class CompanyInfo < ActiveRecord::Base
..
belongs_to :user
end
Query:
class Category < ActiveRecord::Base
..
def total_tradesmen #returns tradesmen with a certain skill-profile
a = self.self_and_all_children_for.collect {|cat| cat.id}
total_tradesmen = User.find_by_sql(
"select *
from users u
inner join preferred_categories pc on pc.user_id = u.id
inner join company_infos ci on ci.user_id = pc.user_id
where pc.category_id in ( #{a.join(',')} )"
)
end
..
end
=> Result: I get only attributes from the users table.
What I need are the attributes from the other tables (preferred_categories, company_infos) as well. Any ideas?
In your case I think that ActiveRecord can handle your query. You should eager load the associations that you need by using include.
total_tradesmen = User.all(
:include => [:company_info, :preferred_categories],
:conditions => {:preferred_categories => {:category_id => a}}
)
Then access the attributes you need on the associated models:
# Examples since I don't know the attributes on your models
company_address = total_tradesmen.first.company_info._address_
preferred_category_names = total_tradesmen.first.preferred_categories.map(&:_name_)
UPDATE
Try specifying joins explicitly
total_tradesmen = User.all(
:include => [:company_info, :preferred_categories],
:joins => [:company_info, :preferred_categories],
:conditions => {:preferred_categories => {:category_id => a}}
)