how do I change my activerecord model default behavior for the find method?
For example, i want to search for all books inside drupal nodes database, but drupal uses only one table for all data, and uses the 'type' column to find out the type
class Book < ActiveRecord::Base
set_table_name 'node'
def find(*args)
:conditions => {:type => 'book'}
super
end
end
this is the correct approach to solve this problem?
I've solved this creating a model for Node and using named_scopes
the result was this
class Node
set_table_name 'node'
set_primary_key 'nid'
named_scope :book, :conditions => {:type => 'book'}
# if i don't overwrite this method, i would get an error when i try to use the type column
def self.inheritance_column
"rails_type"
end
end
it works, but doesn't look like the rails way of doing stuff. If I get enought time soon, I'll try to write a library to access drupal data using something like acts_as_drupal_node
now i can fetch all book entries using:
#books = Node.book.all
Related
I'm working on implementing a tagging system and I'm having problem querying for tagged objects with a scope.
For example, I would like to find all the user's items with a certain tag. With a class method I can currently find all the objects:
def self.tagged_with(name)
Tag.find_by_name(name).items
end
However, this has a problem. If I were to do something like: current_user.items.tagged_with(name) won't this existing method return ALL the items and not just items owned by the current_user? I suppose this is a simply querying issue but I can't figure out how to change a class method into something called on a collection. I have tried going the opposite way, to get a the collection through the tags, something like... tag.items.where(:user_id => current_user.id) but in this case, it's a many-to-many relationship and I haven't been able to get on thumb on this either.
What's the proper way to restrict a query like this?
Create an association on your User class that points to your Tag class.
class User < ActiveRecord::Base
has_many :tags
end
Then you can do:
current_user.tags.where(...)
If you don't already have an association in place, you'll need to create a migration to have the tags table reference your users table with a foreign key.
I think this will help you:
class Account < ActiveRecord::Base
has_many :people do
def find_or_create_by_name(name)
first_name, last_name = name.split(" ", 2)
find_or_create_by_first_name_and_last_name(first_name, last_name)
end
end
end
person = Account.first.people.find_or_create_by_name("David Heinemeier Hansson")
person.first_name # => "David"
person.last_name # => "Heinemeier Hansson"
So, basically you can define your method tagged_with directly into the association!
This example is took from the documentations ActiveRecord::Associations
If I just including nested model in query such this
#projects = current_user.projects.all(include: :reviews)
everything ok. But Review model has some scope, that I need implement in query above. I trying this
#projects = current_user.projects.all(include: :reviews.unreaded)
and gets error. What is the right way to do this?
One option would be to create an association based on the scope, roughly:
#projects = current_user.projects.all(include: :unread_reviews)
Then create an unread_reviews association, roughly:
class Project < ...
has_many :unread_reviews, :conditions => ['read=?', true], :class_name => "Review"
(Replace the above has_many with your association particulars, obviously.)
This technique is discussed in the association docs.
Working on a multi-tenant app where most of my models will have a tenant_id field so I can ensure read permissions by finding through the association (current_tenant.applications.find(params[:id])):
class Application < ActiveRecord::Base
belongs_to :tenant
has_many :app_questions, :conditions => proc {{:tenant_id => tenant_id}}, :dependent => :destroy
end
I like how this allows me to elegantly create a new AppQuestion with the tenant_id set automatically:
#application = current_tenant.applications.find(params[:app_question][:application_id])
#question = #application.app_questions.build(params[:app_question])
#...
Problem is, when I try to use includes() to eager-load the association it throws an error:
current_tenant.applications.where(:id => params[:id]).includes(:app_questions => :app_choices).first
NoMethodError (undefined method `tenant_id' for #<Class:0x007fbffd4a9420>):
app/models/application.rb:7:in `block in <class:Application>'
I could refactor so that I don't have to have the proc in the association conditions, but am wondering if anyone has a better solution.
The ref does say: "If you need to evaluate conditions dynamically at runtime, use a proc"
I've replied to the other question with more details trying to explain why this cannot work.
When they say dynamic is because the proc can be executed at runtime, but not in the context of an existing instance of the Application class because it doesn't exist when you invoke this relation
Application.where(:id => params[:id]).includes(:app_questions => :app_choices)
The ability for :conditions to accept a proc isn't documented in the ref. I suspect it doesn't work the way you guessed it might.
:conditions accepts either an SQL WHERE clause, or a hash that can be turned into on. It's inserted into the SQL that gets the :app_questions records, and if it's a proc it's only called once to get the snippet for the SQL statement to be constructed.
It might help to have a look at your database relationships. Should app_questions link to tenants or applications?
Assuming the relation itself works you could try preload instead of includes
Using Mongoid 2.4.5 on Rails 3.2.1
I have a Model Book that has_many :pages.
class Book
include Mongoid::Document
has_many :pages
end
class Page
include Mongoid::Document
field :page_number
belongs_to :book
validates_uniqueness_of :page_number, scope: :book
end
I'm using nested resources so that I can get urls like /books/4f450e7a84b93e2b44000001/pages/4f4bba1384b93ea750000003/
What I would like to be able to do is use a url like /books/4f450e7a84b93e2b44000001/pages/3/ to get the third page in that book.
Now the crux of the question:
I want to find the page via a call like Book.find('4f450e7a84b93e2b44000001').pages.find('3') or like Book.find('4f450e7a84b93e2b44000001').pages.find('4f4bba1384b93ea750000003')
I know that I can override the find method in Page with something like
class << self
def find(*args)
where(:page_number => args.first).first || super(args)
end
end
But that doesn't seem to have any effect on the scoped query book.pages.find('3') as it seems the scoped search uses a different find method.
How do I specifically override the find method used by book.pages.find('3')?
Why just do a where criteria on your pages ?
Book.find('4f450e7a84b93e2b44000001').pages.where( :page_number => '3')
You can do a scope to in your Pages
class Page
scope :page_number, lambda{|num| where(:page_number => num) }
end
and use it like :
Book.find('4f450e7a84b93e2b44000001').pages.page_number('3')
Define a to_param method on your Page model that returns the page number. This way all Rails URL helpers use that when building URLs (automatically). Then you can just use something like
#book.pages.where(:page_number => params[:page_id]) # page_id is actually the result of page#to_param
Btw. I don't know how large your books are, but it might make more sense to embed your Pages in the Book from a document-oriented database point of view. The whole relationship business is not native to MongoDB.
I am making a site in RoR and I am inside a multi DB environment. By that, I mean that some of my models are linked to MSSQL tables, and some others are linked to MYSQL tables.
It works well for the most part, but when I use the 'include' option in a find method, I get a very weird mix of SQL. Let me show you an example:
[SELECT * FROM "viewInfoClient" WHERE ("viewInfoClient".`NoClient` IN (6044196,5000652,0204392)) ]
MSSQL uses " between tables and columns name
MYSQL uses `
When I use the :include option in a MYSQL model, it will try and go read the corresponding results in the MSSQL model table. Since the NoClient link field comes from my MYSQL model, it gets mixed and MSSQL throws an error which is logical.
[unixODBC][FreeTDS][SQL Server]Incorrect syntax near '`'
Any idea how I can solve this problem?
CLIENT MODEL (MSSQL Database)
class Client < ActiveRecord::Base
establish_connection "mssql_#{RAILS_ENV}"
set_table_name "viewInfoClient"
set_primary_key "NoClient"
has_many :billets, :foreign_key => 'noclient', :primary_key => 'NoClient'
end
BILLET MODEL (MySQL Database)
class Billet < ActiveRecord::Base
belongs_to :client, :foreign_key => 'noclient'
end
AFFECTED STATEMENT
Could be anything using :include in it between the 2.
Example from the Billet model
def findall
find(:all, :include => 'client', :conditions => 'bin_id = 1')
end
Will return:
SELECT * FROM "viewInfoClient" WHERE ("viewInfoClient".`NoClient` IN (6044196,5000652,0204392))
Where (6044196,5000652,0204392) are the 3 records that have bin_id = 1 in the Billet model.
I remove everything else from my models to shorten the code, but this is it basically. I can reproduce it from any model that uses a MySQL - MSSQL link.