I have this model
User.rb
default_scope :order => 'users.created_at DESC'
and
scope :ranking, lambda { unscoped { order('users.ranking DESC') }}
and still I get a to_sql that includes ORDER BY users.created_at DESC, users.ranking DESC...
can someone explain why?
I really don't want to have to call unscoped from every controller i'll be using this model in.
Thanks!
As you're discovering, default_scope is often more trouble than it's worth. If you're wanting to stick with it, you could use reorder to ignore the previous order:
scope :ranking, reorder("ranking DESC")
Not sure why #TimPost deleted my answer but I'm using rails 3.0.5 and ruby 1.9.2 for a project and when I used reorder(which works btw) it says this in the log
DEPRECATION WARNING: reorder is deprecated. Please use except(:order).order(...) instead. (called from <class:Item>
So I don't think it is fair my answer was deleted and I got dinged for a crappy response
Related
here is my ability define:
can :manage,Order,:store => {:business_district => {:district_manager_id => user.id}}
and when I loading resourses by:
Order.accessible_by(current_ability)
It generate SQL like this:
SELECT COUNT(*) FROM `orders` INNER JOIN `stores` ON `stores`.`id` = `orders`.`store_id` INNER JOIN `business_districts` ON `business_districts`.`id` = `stores`.`business_district_id` WHERE (`stores`.`business_districts` = '---\n:district_manager_id: 37\n')
The sql looks all good except code in "where".
I don't know how to make it works
here is the model relation
1. store belongs_to business_district
2. order belongs_to store
3. business_district has district_manager_id
and i want see all orders in business_district
I have found a topic about this in so:[CanCan deeply nested resources
but when use block define in cancan ,you can't use accessible_by(current_ability) load resources!
and your can use Order.joins(:store => :business_district).where("district_manager_id = ?",current_user.id)to load what I want! is there any way cancan gem can do like this?
Update (28 May): The pull request adding deeply nested resource abilities was included in the 1.6.10 release. There is also a fix on GitHub for the SQL conditions bug described below. It should make it into the next release I believe, as it is an obvious mismatch.
Maybe you've figured this out by now, but for anybody else who might stop by here before searching the issues page for CanCan on github....
There's a pull request that was accepted about 2 months ago that addresses this. Check https://github.com/ryanb/cancan/pull/806 .
As of CanCan 1.6.9 this changeset wasn't incorporated so for now one has to use the master branch. As it stands though, the changeset introduces another bug from what I can tell, it fails for 2-condition ability definition, even in the non-nested case. For example, I've found that the following (I am using your models for naming...) fails:
can :manage, Order,:store => {:district_manager_id => user.id, :condition2 => true}
whereas the following is ok:
can :manage, Order,:store => {:district_manager_id => user.id }
I've also posted on the GitHub issue page about this.
I'm In the process of migrating from Rails 2.3.11 to Rails 3.1.3 and I am now on Rails 3.0.11 and sorting out all the issues that this brings.
The first one I can't solve is: in Rails 2.3.11, I could do the following and get the required records back
#event_type_time_units = TimeUnit.find(#event.event_type.time_units)
In Rails 3.0.11, I've tried using
#event_type_time_units = TimeUnit.find_with_ids(#event.event_type.time_units)
and
#event_type_time_units = TimeUnit.find_some(#event.event_type.time_units)
The code for both of those doesn't do anything magical and I expected them not to work.
Does anyone have a pointer for me, please.
Thank you
edit: the error I get is TypeError in MeetingsController#create
Cannot visit TimeUnit
Rails 3 uses Arel aka relational algebra to fetch associations. Assuming your EventType model has an association to has_many :time_units, you can just do the following:
#event_type_time_units = #event.event_type.time_units
Furthermore, you can optimize your queries using EventType as a join model (ish):
# app/models/event.rb
belongs_to :event_type
has_many :time_units, :through => :event_type
# app/models/event_type.rb
has_many :events
has_many :time_units
Now, you can query directly, saving a SQL call:
#event_time_units = #event.time_units
In short, there's no reason to do a find on an association. The association returns an "Array" of the records. (I use "Array" in quotes, because it's not really an array, but an ActiveRecord::Association which behaves much like an array)
Aside
I highly recommend just migrating to Rails 3.1.3. It's just as difficult to migrate from Rails 2 -> 3 as 3 => 3.1. Save yourself the middle headache. In fact, given the legacy of your application, I recommend the following:
Create a new, empty Rails 3.1.3 application
Copy all your models, views, controllers, and libs to this new application
Search your existing projects for gems -> add them to your Gemfile
Review everything in config/*. This is where a LOT of changes have take place. If you have application-specific code in your existing application, port it over to the new one. Otherwise, leave it alone.
So, I tried to search for an example of how to do this, and I'm not sure I even know how to describe what I'm trying to do. I'm an utter noob when it comes to SQL, and I'm sure this is really basic but I'm totally lost:
I have a model, Photo, which has_many :tags, :through => :taggings. Tags have a name and an id.
I want to do something like: Photo.where( #tag_name in [array] )
... but like I said I have no idea how to write something like that, or what to search to see an example on Google.
Can anyone give me an example of that kind of query, and what it might be called?
Thanks!
Just tried this on a similar model of my own and seemed to work fine:
Photo.joins(:tags).where('tags.name' => ['herp','derp']).group(:id)
Also, here's a great resource on the AREL querying interface rails 3 uses, with information on these and other ActiveRecord calls related to querying.
So, as a twist on Brett's method, it turns out the following works without breaking PostgreSQL:
def self.tagged_with( string )
array = string.split(',').map{ |s| s.lstrip }
select('distinct photos.*').joins(:tags).where('tags.name' => array )
end
Problem solved! See this article for a great explanation as to why this is a better idea than 'group'.
Apologies for the long title, but this is bothering me. I'm new to Rails, so this is my first project. Rails 3.0.3.
In my model, a User may or may not have read many Entries; this is tracked in a model called ReadEntries. This many-to-one relationship is properly defined in the code, I think.
User.rb:
has_many :read_entries
Entry.rb:
has_many :read_entries
ReadEntry.rb:
belongs_to :entry
belongs_to :user
This table has to be populated at some point. If I try to do this:
user.read_entries.find_or_create_by_entry_id(entry.id, :read => false)
I get the error Unknown key(s): read. Leave out trying to set :read, and it works.
However, if I create the same row with this, it works:
ReadEntry.find_or_create_by_entry_id_and_user_id(entry.id, user.id, :read => false)
Logically, these methods should be identical, right? Thanks.
I've also had weird experiences with find_or_create. I would love it if it worked, but it seems inconsistent.
I'm currently having the same issue as you, and I think it may be due to calling find_or_create on an association as opposed to the model directly. Here's my example:
permission_assignments.find_or_create_by_role_id(:role_id => role_id, :is_allowed => false)
This works to create the assignment, except the "is_allowed" field gets set to it's default of "true". This code works for me (in the Permission model, hence the self reference)
PermissionAssignment.find_or_create_by_permission_id_and_role_id(:permission_id => self.id, :role_id => role_id, :is_allowed => false)
It's more verbose, unfortunately, but it works. The only problem that I still notice is that the object that is returned has no id assigned (the record does get created in the database, however, but if I wanted to update any more attributes I wouldn't be able to without the id). Don't know if that's a separate issue or not.
Rails 3.0.4 here with Postgres 8.4
You cannot pass in other fields like that as Rails will assume they are options for the find. Instead, you will need to make your method call longer:
user.read_entries.find_or_create_by_entry_id_and_read(entry.id, false)
Or alternatively use a shorter, custom syntax for that.
For your final example, my thoughts are that Rails will take the second argument and use that as options. Other than that, I am not sure.
I would like to see the SQL statement that a given ActiveRecord Query will generate. I recognize I can get this information from the log after the query has been issued, but I'm wondering if there is a method that can be called on and ActiveRecord Query.
For example:
SampleModel.find(:all, :select => "DISTINCT(*)", :conditions => ["`date` > #{self.date}"], :limit => 1, :order => '`date`', :group => "`date`")
I would like to open the irb console and tack a method on the end that would show the SQL that this query will generate, but not necessarily execute the query.
Similar to penger's, but works anytime in the console even after classes have been loaded and the logger has been cached:
For Rails 2:
ActiveRecord::Base.connection.instance_variable_set :#logger, Logger.new(STDOUT)
For Rails 3.0.x:
ActiveRecord::Base.logger = Logger.new(STDOUT)
For Rails >= 3.1.0 this is already done by default in consoles. In case it's too noisy and you want to turn it off you can do:
ActiveRecord::Base.logger = nil
Stick a puts query_object.class somewhere to see what type of object your working with, then lookup the docs.
For example, in Rails 3.0, scopes use ActiveRecord::Relation which has a #to_sql method. For example:
class Contact < ActiveRecord::Base
scope :frequently_contacted, where('messages_count > 10000')
end
Then, somewhere you can do:
puts Contact.frequently_contacted.to_sql
just use to_sql method and it'll output the sql query that will be run. it works on an active record relation.
irb(main):033:0> User.limit(10).where(:username => 'banana').to_sql
=> "SELECT "users".* FROM "users" WHERE "users"."username" = 'banana'
LIMIT 10"
when doing find, it won't work, so you'll need to add that id manually to the query or run it using where.
irb(main):037:0* User.where(id: 1).to_sql
=> "SELECT "users".* FROM "users" WHERE "users"."id" = 1"
This may be an old question but I use:
SampleModel.find(:all,
:select => "DISTINCT(*)",
:conditions => ["`date` > #{self.date}"],
:limit=> 1,
:order => '`date`',
:group => "`date`"
).explain
The explain method will give quite a detailed SQL statement on what its going to do
This is what I usually do to get SQL generated in console
-> script/console
Loading development environment (Rails 2.1.2)
>> ActiveRecord::Base.logger = Logger.new STDOUT
>> Event.first
You have to do this when you first start the console, if you do this after you have typed some code, it doesn't seem to work
Can't really take credit for this, found it long time ago from someone's blog and can't remember whose it is.
When last I tried to do this there was no official way to do it. I resorted to using the function that find and its friends use to generate their queries directly. It is private API so there is a huge risk that Rails 3 will totally break it, but for debugging, it is an ok solution.
The method is construct_finder_sql(options) (lib/active_record/base.rb:1681) you will have to use send because it is private.
Edit: construct_finder_sql was removed in Rails 5.1.0.beta1.
Create a .irbrc file in your home directory and paste this in:
if ENV.include?('RAILS_ENV') && !Object.const_defined?('RAILS_DEFAULT_LOGGER')
require 'logger'
RAILS_DEFAULT_LOGGER = Logger.new(STDOUT)
end
That will output SQL statements into your irb session as you go.
EDIT: Sorry that will execute the query still, but it's closest I know of.
EDIT: Now with arel, you can build up scopes/methods as long as the object returns ActiveRecord::Relation and call .to_sql on it and it will out put the sql that is going to be executed.
My typical way to see what sql it uses is to introduce a "bug" in the sql, then you'll get an error messages spit out to the normal logger (and web screen) that has the sql in question. No need to find where stdout is going...
Try the show_sql plugin. The plugin enables you to print the SQL without running it
SampleModel.sql(:select => "DISTINCT(*)", :conditions => ["`date` > #{self.date}"], :limit => 1, :order => '`date`', :group => "`date`")
You could change the connection's log method to raise an exception, preventing the query from being run.
It's a total hack, but it seems to work for me (Rails 2.2.2, MySQL):
module ActiveRecord
module ConnectionAdapters
class AbstractAdapter
def log_with_raise(sql, name, &block)
puts sql
raise 'aborting select' if caller.any? { |l| l =~ /`select'/ }
log_without_raise(sql, name, &block)
end
alias_method_chain :log, :raise
end
end
end
You can simply use to_sql() function with the active record
Form.where(status:"Active").to_sql
In Rails 3 you can add this line to the config/environments/development.rb
config.active_record.logger = Logger.new(STDOUT)
It will however execute the query. But half got answered :