I want to delete some users and duplicate tags that are in my db. Is there a way I can use rails console to list all of these objects so I can pinpoint each one to delete them. They are not necessarily the last entries?
Assuming your model is derived from ActiveRecord::Base and named User, you can do
with rails console
pp User.all # all users
or
pp User.all(:conditions => {:firstname => 'fred'}) # use hash conditions
or
pp User.all(:conditions => "lastname LIKE 'jenkin%'") # use custom sql conditions
and having the right user (say, id 42), you can do
User.delete(42)
That pp stands for pretty print. Another sometimes handy is y which prints stuff in Yaml format.
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.
Currently, I have a User object that has a field realname. I'm trying to split on the space and convert it to two fields, first_name and last_name. Below is the script that I wrote to do this:
User.all.each do |user|
puts "Updating #{user.realname}"
name = user.realname.split(' ')
user.first_name = name[0]
user.last_name = name[1]
user.save
puts "Saved #{user.first_name} #{user.last_name}"
sleep(1)
end
When I run this using rails runner in my development environment, many of the first half of the users aren't not getting updated. Although the output from the script is perfect, when I look at what is saved in mongo, some users don't have these new fields.
Are you sure those users are valid?
Try using user.save! instead of user.save.
If you want to save this nevertheless then you can bypass validations by calling:
user.save(validate: false)
Try looking for a changed default_scope on your User class.
If the default scope have been changed, then User#All will not mean "all objects available on DB".
Quick question about eager loading. I have the following code:
#user =
User.includes(:restaurants).find_by_unique_identifier(params[:unique_identifier])
However, I only want to load restaurants associated with a given user only if the restaurants have a list_id of X (which is one of the columns of the restaurants table).
How would I go about this?
I tried the following, but it still loaded all the restaurant records associated with the user.
#user = User.includes(:restaurants).where(:restaurants => {:list_id => params[:list_id]}).find_by_unique_identifier(params[:unique_identifier])
Assuming you have all the associations requirements setup, then you can use joins:
#user = User.all(:conditions =>["restaurants.list_id = ?", params[:list_id] ], :joins => [:restaurants])
UPDATE:
My code fetches a list of users. However, You can use your filtering methods to narrow down the list or get the individual records.
I've just created two models and one "join table". Person, Adress (create_adresses_personss)
class Person < ActiveRecord::Base
has_and_belongs_to_many :streets
end
class Street < ActiveRecord::Base
has_and_belongs_to_many :persons
end
Now I want to add some data to these models in the db/seeds.rb file. The tutorial I follow just adds the objects:
person = Person.create :name => 'Dexter'
street.create[{:streetname => 'street1'},
{:streetname => 'street2'},
{:streetname => 'julianave'},
{:streetname => 'street3'}]
Question 1: Why is persons' data added differently than streets'? Is it just the tutorial that wants to show that there are many ways of adding data in the seeds.rb?
Question 2: The tutorial doesn't make the connections/joins in the seeds.rb. It does that in the rails console;
>>p1 = Person.find(1)
>>s1 = Street.find(1)
>>p1.streets << s1
Can't theese connections be made in the seeds.rb file?
Question 3: Would it be better to do this join with a "rich many_to_many-assocciation"?
Thanks for your time and patience with a beginner ;)
1) The first method is creating one object. The second method is creating multiple objects. However, for the second method you would need to do Street.create, not street.create.
2) Yes, you can do that in the seed file the same way.
3) The "Rich many-to-many" you're talking about is an association with a Join Model, I guess you're talking about. This is opposed to just a join table, which is what has_and_belongs_to_many does. To use a join model, you'll want to look up has_many :through. It's generally considered better to always use a proper join model, however I still use HABTM when I just need a quick, simple association. has_many :through allows for more options and more flexibility, but it is a little more complicated to setup (not that much, though). It's your decision.
One way that I like to create seed data for many-to-many associations is setting up one of the models, the adding a tap block that sets up the other models through the association.
Person.create!(:name => "Fubar").tap do |person|
3.times do |n|
person.streets.create!(:streetname => "street #{n}")
end
# OR
person.streets.create!([
{:streetname => "street 1"},
{:streetname => "street 2"},
... and so on
])
end
All tap is doing is executing the block with the object as it's only parameter. I find it convenient for seeds.
One other tip I would toss out there would be to have your model attribute names spaced on the words with underscores.
:street_name instead of :streetname
The difference is more profound when you start wanting to use some of the ActiveSupport helers that take model attributes and turn them into text strings for use in the UI.
e
:streetname.to_s.titleize # "Streetname"
:street_name.to_s.titleize # "Street Name"
And one last nitpick, you might want your join table to be addresses_people not addresses_persons since the rais inflector is going to pluralize person as people. The same would go for your controller on the Person model, PeopleController instead of PersonsController. Though maybe it will work with persons as well.
:person.to_s.pluralize # "people"
:people.to_s.singularize # "person"
:persons.to_s.singularize # "person"
See the updates at the bottom. I've narrowed this down significantly.
I've also created a barebones app demonstrating this bug: https://github.com/coreyward/bug-demo
And I've also created a bug ticket in the official tracker: https://rails.lighthouseapp.com/projects/8994/tickets/6611-activerecord-query-changing-when-a-dotperiod-is-in-condition-value
If someone can either tell me how to monkey-patch this or explain where this is happening in Rails I'd be very grateful.
I'm getting some bizarre/unexpected behavior. That'd lead me to believe either there is a bug (confirmation that this is a bug would be a perfect answer), or I am missing something that is right under my nose (or that I don't understand).
The Code
class Gallery < ActiveRecord::Base
belongs_to :portfolio
default_scope order(:ordinal)
end
class Portfolio < ActiveRecord::Base
has_many :galleries
end
# later, in a controller action
scope = Portfolio.includes(:galleries) # eager load galleries
if some_condition
#portfolio = scope.find_by_domain('domain.com')
else
#portfolio = scope.find_by_vanity_url('vanity_url')
end
I have Portfolios which can have multiple Galleries each.
The galleries have ordinal, vanity_url, and domain attributes.
The gallery ordinals are set as integers from zero on up. I've confirmed that this works as expected by checking Gallery.where(:portfolio_id => 1).map &:ordinal, which returns [0,1,2,3,4,5,6] as expected.
Both vanity_url and domain are t.string, :null => false columns with unique indexes.
The Problem
If some_condition is true and find_by_domain is run, the galleries returned do not respect the default scope. If find_by_vanity_url is run, the galleries are ordered according to the default scope. I looked at the queries being generated, and they are very different.
The Queries
# find_by_domain SQL: (edited out additional selected columns for brevity)
Portfolio Load (2.5ms) SELECT DISTINCT `portfolios`.id FROM `portfolios` LEFT OUTER JOIN `galleries` ON `galleries`.`portfolio_id` = `portfolios`.`id` WHERE `portfolios`.`domain` = 'lvh.me' LIMIT 1
Portfolio Load (0.4ms) SELECT `portfolios`.`id` AS t0_r0, `portfolios`.`vanity_url` AS t0_r2, `portfolios`.`domain` AS t0_r11, `galleries`.`id` AS t1_r0, `galleries`.`portfolio_id` AS t1_r1, `galleries`.`ordinal` AS t1_r6 FROM `portfolios` LEFT OUTER JOIN `galleries` ON `galleries`.`portfolio_id` = `portfolios`.`id` WHERE `portfolios`.`domain` = 'lvh.me' AND `portfolios`.`id` IN (1)
# find_by_vanity_url SQL:
Portfolio Load (0.4ms) SELECT `portfolios`.* FROM `portfolios` WHERE `portfolios`.`vanity_url` = 'cw' LIMIT 1
Gallery Load (0.3ms) SELECT `galleries`.* FROM `galleries` WHERE (`galleries`.portfolio_id = 1) ORDER BY ordinal
So the query generated by find_by_domain doesn't have an ORDER statement, hence things aren't being ordered as desired. My question is...
Why is this happening? What is prompting Rails 3 to generate different queries to these two columns?
Update
This is really strange. I've considered and ruled out all of the following:
Indexes on the columns
Reserved/special words in Rails
A column name collision between the tables (ie. domain being on both tables)
The field type, both in the DB and Schema
The "allow null" setting
The separate scope
I get the same behavior as find_by_vanity_url with location, phone, and title; I get the same behavior as find_by_domain with email.
Another Update
I've narrowed it down to when the parameter has a period (.) in the name:
find_by_something('localhost') # works fine
find_by_something('name_routed_to_127_0_0_1') # works fine
find_by_something('my_computer.local') # fails
find_by_something('lvh.me') #fails
I'm not familiar enough with the internals to say where the query formed might change based on the value of a WHERE condition.
The difference between the two strategies for eager loading are discussed in the comments here
https://github.com/rails/rails/blob/3-0-stable/activerecord/lib/active_record/association_preload.rb
From the documentation:
# The second strategy is to use multiple database queries, one for each
# level of association. Since Rails 2.1, this is the default strategy. In
# situations where a table join is necessary (e.g. when the +:conditions+
# option references an association's column), it will fallback to the table
# join strategy.
I believe that the dot in "foo.bar" is causing active record to think that you are putting a condition on a table that is outside of the originating model which prompts the second strategy discussed in the documentation.
The two separate queries runs one with the Person model and the second with the Item model.
Person.includes(:items).where(:name => 'fubar')
Person Load (0.2ms) SELECT "people".* FROM "people" WHERE "people"."name" = 'fubar'
Item Load (0.4ms) SELECT "items".* FROM "items" WHERE ("items".person_id = 1) ORDER BY items.ordinal
Because you run the second query against the Item model, it inherits the default scope where you specified order(:ordinal).
The second query, which it attempts eager loading with the full runs off the person model and will not use the default scope of the association.
Person.includes(:items).where(:name => 'foo.bar')
Person Load (0.4ms) SELECT "people"."id" AS t0_r0, "people"."name" AS t0_r1,
"people"."created_at" AS t0_r2, "people"."updated_at" AS t0_r3, "items"."id" AS t1_r0,
"items"."person_id" AS t1_r1, "items"."name" AS t1_r2, "items"."ordinal" AS t1_r3,
"items"."created_at" AS t1_r4, "items"."updated_at" AS t1_r5 FROM "people" LEFT OUTER JOIN
"items" ON "items"."person_id" = "people"."id" WHERE "people"."name" = 'foo.bar'
It is a little buggy to think that, but I can see how it would be with the several different ways you can present a list of options, the way to be sure that you catch all of them would be to scan the completed "WHERE" conditions for a dot and use the second strategy, and they leave it that way because both strategies are functional. I would actually go as far as saying that the aberrant behavior is in the first query, not the second. If you would like the ordering to persist for this query, I recommend one of the following:
1) If you want the association to have an order by when it is called, then you can specify that with the association. Oddly enough, this is in the documentation, but I could not get it to work.
Source: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many
class Person < ActiveRecord::Base
has_many :items, :order => 'items.ordinal'
end
2) Another method would be to just add the order statement to the query in question.
Person.includes(:items).where(:name => 'foo.bar').order('items.ordinal')
3) Along the same lines would be setting up a named scope
class Person < ActiveRecord::Base
has_many :items
named_scope :with_items, includes(:items).order('items.ordinal')
end
And to call that:
Person.with_items.where(:name => 'foo.bar')
This is issue #950 on the Rails GitHub project. It looks like implicit eager loading (which is what causes this bug) has been deprecated in Rails 3.2 and removed in Rails 4.0. Instead, you'll explicitly tell Rails that you need a JOIN for the WHERE clause — e.g.:
Post.includes(:comments).where("comments.title = 'lol'").references(:comments)
If you desperately need this bug fixed in Rails 3.1.*, you can hack ActiveRecord::Relation#tables_in_string to be less aggressive in matching table names. I created a Gist of my (inelegant and slow) solution. This is the diff:
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 30f1824..d7335f3 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
## -528,7 +528,13 ## module ActiveRecord
return [] if string.blank?
# always convert table names to downcase as in Oracle quoted table names are in uppercase
# ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
- string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map{ |s| s.downcase }.uniq - ['raw_sql_']
+ candidates = string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map{ |s| s.downcase }.uniq - ['raw_sql_']
+ candidates.reject do |t|
+ s = string.partition(t).first
+ s.chop! if s.last =~ /['"]/
+ s.reverse!
+ s =~ /^\s*=/
+ end
end
end
end
It only works for my very specific case (Postgres and an equality condition), but maybe you can alter it to work for you.