How to full join two rail models? - ruby-on-rails

I'm trying to join the results of 'SupplierShippingItem' and 'MtlSystemItem' but I keep getting an error:
Association named 'mtl_system_items' was not found; perhaps you misspelled it?
My association is done like this:
SupplierShippingItem.joins(:mtl_system_items).where('supplier_shipping_items.inventory_item_id = mtl_system_items.inventory_item_id SEGMENT1 ILIKE ? OR DESCRIPTION ILIKE ? ', "%#{params[:term]}%", "%#{params[:term]}%")
SupplierShippingItem
class SupplierShippingItem < ActiveRecord::Base
attr_accessible :inventory_item_id, :received_qty, :shipped_qty, :supplier_shipping_list_id, :supplier_planning_schedule_id, :po_number
belongs_to :mtl_system_item, :foreign_key => :inventory_item_id
end
*MtlSystemItem *
class MtlSystemItem < ActiveRecord::Base
attr_accessible :inventory_item_id, :segment1, :description, :primary_uom_code, :inventory_item_status_code, :item_type
has_many :supplier_shipping_items, :foreign_key => :inventory_item_id
end
What I'm trying to achieve is to fetch the items in MtlSystemItem but only if they are found in SupplierShippingItem. I have thousands of items in MtlSystemItem so I want to filter them out a bit. I'll also include a date restriction later on, but I'm blocked by the error.

as the error says, the association is not found. You used mtl_system_items instead of mtl_system_item (singular) which is the association you declared.
Remember that for joins and includes, you need to use the association name. For where, use the table name
SupplierShippingItem.joins(:mtl_system_item)
.where('supplier_shipping_items.inventory_item_id = mtl_system_items.inventory_item_id SEGMENT1 ILIKE ? OR DESCRIPTION ILIKE ? ', "%#{params[:term]}%", "%#{params[:term]}%")

SupplierShippingItem.joins(:mtl_system_items)
should be
SupplierShippingItem.joins(:mtl_system_item)
on your example above:
class SupplierShippingItem < ActiveRecord::Base
belongs_to :mtl_system_item
end
class MtlSystemItem < ActiveRecord::Base
has_many :supplier_shipping_items
end
you can try this ActiveRecord joins:
SupplierShippingItem.find(:all, :joins => :mtl_system_item])
and you can add conditions for this query like this:
SupplierShippingItem.find(:all, :joins => :mtl_system_item, :conditions => ["supplier_shipping_items.id = ?", 1]])

Related

Sort has_many relation in rails 3

my model is
class Job < ActiveRecord::Base
belongs_to :client
end
class Client < ActiveRecord::Base
has_many :jobs
end
in controller i want get client with sorted jobs.
If i do (without ordering)
#client = Client.find(params[:id], :include => {:jobs => :status})
It is all ok. But if i add ordering:
#client = Client.find(params[:id], :include => {:jobs => :status}, :order => 'job.level DESC')
// :order is dynamicly set (not in this example) - i know about :order in has_many.
the result is only 3 rows (for every job.level one). I logged the sql query and executed it and result is ok, but in app i have only these 3 rows.
What is the right way to sort jobs? Thank you
You could try specifying the order directly in the model instead of the controller
class Job < ActiveRecord::Base
belongs_to :client, :order => 'level DESC'
end
OR
class Client < ActiveRecord::Base
has_many :jobs, :order => 'level DESC'
end
Also, what data type is the level in the Jobs model? If you could post your logs for the sql queries that would be helpful as well. Also, have you tried
:order => 'jobs.level'
instead of the singular job.level used in the code you posted?
This is not what i originally wanted, but it works, so this is answer
#jobs = #client.jobs.find(:all, :order => sort_column + " " + sort_direction)

Help with a Join in Rails 3

I have the following models:
class Event < ActiveRecord::Base
has_many :action_items
end
class ActionItem < ActiveRecord::Base
belongs_to :event
belongs_to :action_item_type
end
class ActionItemType < ActiveRecord::Base
has_many :action_items
end
And what I want to do is, for a given event, find all the action items that have an action item type with a name of "foo" (for example). So I think the SQL would go something like this:
SELECT * FROM action_items a
INNER JOIN action_item_types t
ON a.action_item_type_id = t.id
WHERE a.event_id = 1
AND t.name = "foo"
Can anybody help me translate this into a nice active record query? (Rails 3 - Arel)
Thanks!
Well I think I solved it myself. Here's what I did
e = Event.find(1)
e.action_items.joins(:action_item_type).where("action_item_types.name = ?", "foo")
Ehm, why not define
has_many :action_item_types, :through => :action_items
and refer to
e.action_item_types.where(:name => "foo")
?
or (as long as "name" is a unique column name)
e.action_items.joins(:action_item_type).where(:name => "foo")

Rails: Query to get recent items based on the timestamp of a polymorphic association

I have the usual polymorphic associations for comments:
class Book < ActiveRecord::Base
has_many :comments, :as => :commentable
end
class Article < ActiveRecord::Base
has_many :comments, :as => :commentable
end
class Comment < ActiveRecord::Base
belongs_to :commentable, :polymorphic => true
end
I'd like to be able to define Book.recently_commented, and Article.recently_commented based on the created_at timestamp on the comments. Right now I'm looking at a pretty ugly find_by_SQL query to do this with nested selects. It seems as though there must be a better way to do it in Rails without resorting to SQL.
Any ideas? Thanks.
For what it's worth, here's the SQL:
select * from
(select books.*,comments.created_at as comment_date
from books inner join comments on books.id = comments.commentable_id
where comments.commentable_type='Book' order by comment_date desc) as p
group by id order by null;
Sometimes it's just best to add a field to the object of which you are commenting. Like maybe a commented_at field of datetime type. When a comment is made on an object, simply update that value.
While it is possible to use SQL to do it, The commented_at method may prove to be much more scalable.
Not sure what your method has looked like previously but I'd start with:
class Book < ActiveRecord::Base
def self.recently_commented
self.find(:all,
:include => :comments,
:conditions => ['comments.created_at > ?', 5.minutes.ago])
end
end
This should find all the books that have had a comment created on them in the last 5 minutes. (You might want to add a limit too).
I'd also be tempted to create a base class for this functionality to avoid repeating the code:
class Commentable < ActiveRecord::Base
self.abstract_class = true
has_many :comments, :as => :commentable
def self.recently_commented
self.find(:all,
:include => :comments,
:conditions => ['comments.created_at > ?', Time.now - 5.minutes])
end
end
class Book < Commentable
end
class Article < Commentable
end
Also, you might want to look at using a plugin to achieve this. E.g. acts_as_commentable.

update_all through an association

I am trying to use update_all through an association, and i am getting mysql errors, anyone know why please?
class Basket < ActiveRecord::Base
has_many :basket_items
has_many :articles, :through => :basket_items
def activate_articles
articles.update_all :active => true
end
end
class BasketItem < ActiveRecord::Base
belongs_to :basket
belongs_to :item
belongs_to :article
end
Mysql::Error: Unknown column 'basket_items.basket_id' in 'where clause': UPDATE `articles` SET `active` = 1 WHERE ((`basket_items`.basket_id = 114))
http://dev.rubyonrails.org/ticket/5353
Looks like there was a problem with n-n associations using has_many :through and using update all. Nothing seems to have been done.
1-n associations do appear to work.
Bug?
dev.rubyonrails moved it's tickets to github's issue tracker. Here is the moved link: https://github.com/rails/rails/issues/522
#nolman posted this help on the ticket
#daicoden and I at #square were pairing on this and we were able to put something together along the lines of:
class Comment
class << self
def trash_all
sql = "UPDATE #{quoted_table_name} "
add_joins!(sql, {})
sql << "SET #{sanitize_sql_for_assignment({:trashed => true})} "
add_conditions!(sql, {})
connection.execute(sql)
end
end
end
Now you can call todolist.comments(:conditions => {:trashed => false}).trash_all
This results in the following SQL:
UPDATE `comments` INNER JOIN `todos` ON `todos`.id = `comments`.todo_id SET `trashed` = 1 WHERE (`comments`.`trashed` = 0 AND `todos`.`todolist_id` = 968316918)
Hope this helps!

Rails: order using a has_many/belongs_to relationship

I was wondering if it was possible to use the find method to order the results based on a class's has_many relationship with another class. e.g.
# has the columns id, name
class Dog < ActiveRecord::Base
has_many :dog_tags
end
# has the columns id, color, dog_id
class DogTags < ActiveRecord::Base
belongs_to :dog
end
and I would like to do something like this:
#result = DogTag.find(:all, :order => dog.name)
thank you.
In Rails 4 it should be done this way:
#result = DogTag.joins(:dog).order('dogs.name')
or with scope:
class DogTags < ActiveRecord::Base
belongs_to :dog
scope :ordered_by_dog_name, -> { joins(:dog).order('dogs.name') }
end
#result = DogTags.ordered_by_dog_name
The second is easier to mock in tests as controller doesn't have to know about model details.
You need to join the related table to the request.
#result = DogTag.find(:all, :joins => :dog, :order => 'dogs.name')
Note that dogs is plural in the :order statement.

Resources