Adding scopes breaks migrations (Rails 3 beta 4)

128 views
Skip to first unread message

Paul Campbell

unread,
Jul 2, 2010, 6:57:30 AM7/2/10
to rubyonra...@googlegroups.com
I came across an interesting issue this morning using Rails 3 beta 4.

in my user.rb I have a scope:

scope :public, where(:private => false)

This was absolutely fine when I added the scope, since the "private"
field was in the database.

I wanted to modify the migration, so I rolled back the database, but
by doing so, I nuked the private field.

Now when I try to rollback or run any migrations, I get:

No attribute named `private` exists for table `users`

Full Trace:
http://gist.github.com/461216

This is happening (I think) because Rails is building the predicate
for the scope at runtime ... when the field doesn't exist.

Whenever something like this happened in Rails 2, I'd normally put the
class inside the migration, eg:

class AddUsernameToUser < ActiveRecord::Migration

class User < ActiveRecord::Base
end

def self.up
add_column :users, :username, :string
add_column :users, :private, :boolean, :default => false
end

def self.down
remove_column :users, :private
remove_column :users, :username
end
end

This doesn't work in this case, because it all happens before _any_
migration is run.

So basically, I have to remove the scope to run any migrations.

This is fine for now, as I can move on with development, but the
implication is that if I start off with a clean database, and run rake
db:migrate, it won't work.

Now, I know that best practice is to use rake db:schema:load, but I
think that this is still a brittle case.

Basically, by adding a scope that depends on a field existing, all
prior migrations break.

—Paul

--

Paul Campbell
pa...@hypertiny.ie
- - - - - - - - - - - - - - - - - - -
web http://hypertiny.ie
blog http://www.pabcas.com
twitter http://www.twitter.com/paulca
github http://www.github.com/paulca
phone +353 87 914 8162
- - - - - - - - - - - - - - - - - - -

Ernie Miller

unread,
Jul 2, 2010, 7:54:34 AM7/2/10
to rubyonra...@googlegroups.com
I think the article entitled "Named Scopes Are Dead" had some good
insights along those lines.

http://www.railway.at/2010/03/09/named-scopes-are-dead/

In the Rails 3 app I've been working on, my scopes are just class
methods like shown there.

> --
> You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group.
> To post to this group, send email to rubyonra...@googlegroups.com.
> To unsubscribe from this group, send email to rubyonrails-co...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
>

Pratik

unread,
Jul 2, 2010, 7:58:44 AM7/2/10
to rubyonra...@googlegroups.com
I swear I had fixed this. Will have another look.

--
Programmer @ 37signals | http://twitter.com/lifo | http://m.onkey.org

Paul Campbell

unread,
Jul 2, 2010, 8:40:15 AM7/2/10
to rubyonra...@googlegroups.com
On Fri, Jul 2, 2010 at 12:58 PM, Pratik <prati...@gmail.com> wrote:
> I swear I had fixed this. Will have another look.

It may be fixed in edge, I'm working off beta4. Will switch to edge
and double check.

—P

Ernie Miller

unread,
Jul 2, 2010, 9:03:12 AM7/2/10
to rubyonra...@googlegroups.com
Pratik, seems like you're right. A quick glance at the scoped method looks like it should be deferring any attempt to actually call a condition until the scope is used, not when it's defined. From Paul's trace, it looks like he is running into an issue caused by the devise_for stuff in his routes file. (Sorry José!) It may also be related to the questionable choice of defining an attribute based on a Ruby keyword (private).

/Users/paul/.rvm/gems/ree-1.8.7-2010.02@roadio/gems/devise-1.1.rc2/lib/devise/mapping.rb:88:in `to'
/Users/paul/.rvm/gems/ree-1.8.7-2010.02@roadio/gems/devise-1.1.rc2/lib/devise/rails/routes.rb:95:in `devise_for'
/Users/paul/.rvm/gems/ree-1.8.7-2010.02@roadio/gems/devise-1.1.rc2/lib/devise/rails/routes.rb:91:in `each'
/Users/paul/.rvm/gems/ree-1.8.7-2010.02@roadio/gems/devise-1.1.rc2/lib/devise/rails/routes.rb:91:in `devise_for'
/Users/paul/Dropbox/Sites/roadio/roadio/config/routes.rb:6


On a related note, time for me to go back and change my class method definitions back to scopes. :)

Rob Biedenharn

unread,
Jul 2, 2010, 9:07:35 AM7/2/10
to rubyonra...@googlegroups.com

On Jul 2, 2010, at 8:40 AM, Paul Campbell wrote:

> On Fri, Jul 2, 2010 at 12:58 PM, Pratik <prati...@gmail.com> wrote:
>> I swear I had fixed this. Will have another look.
>
> It may be fixed in edge, I'm working off beta4. Will switch to edge
> and double check.
>
> —P

If you are using 1.9.2, you may also want to check which revision of
Ruby you're using. (Yes, revision as it the SVN trunk number.) There
was a constant lookup bug for a little while which may have
contributed to this problem, too.

-Rob

>> --
>> Programmer @ 37signals | http://twitter.com/lifo | http://m.onkey.org
>>
>> --
>> You received this message because you are subscribed to the Google
>> Groups "Ruby on Rails: Core" group.
>> To post to this group, send email to rubyonra...@googlegroups.com
>> .

>> To unsubscribe from this group, send email to rubyonrails-co...@googlegroups.com
>> .
>> For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en
>> .
>>
>>
>
>
>

> --
>
> Paul Campbell
> pa...@hypertiny.ie
> - - - - - - - - - - - - - - - - - - -
> web http://hypertiny.ie
> blog http://www.pabcas.com
> twitter http://www.twitter.com/paulca
> github http://www.github.com/paulca
> phone +353 87 914 8162
> - - - - - - - - - - - - - - - - - - -
>
> --
> You received this message because you are subscribed to the Google
> Groups "Ruby on Rails: Core" group.

> To post to this group, send email to rubyonrails-
> co...@googlegroups.com.

Paul Campbell

unread,
Jul 2, 2010, 9:11:45 AM7/2/10
to rubyonra...@googlegroups.com
Ernie, Pratik,

On Fri, Jul 2, 2010 at 2:03 PM, Ernie Miller <er...@metautonomo.us> wrote:
> Pratik, seems like you're right. A quick glance at the scoped method looks
> like it should be deferring any attempt to actually call a condition until
> the scope is used, not when it's defined. From Paul's trace, it looks like
> he is running into an issue caused by the devise_for stuff in his routes
> file. (Sorry José!) It may also be related to the questionable choice of

Sorry about the false alarm ... removing "devise_for" in the routes
"fixes" this, so it looks like it is a devise issue.

Definitely something I can live with in the short term.

> defining an attribute based on a Ruby keyword (private).

I'm pretty sure this isn't the case, since there's no "private" method
name. Interestingly, it's very difficult to come up for a name in this
that isn't a potential collision.

"private" and "public" being the most obvious choices, even
"anonymous" doesn't really work.

Anyway, thanks for your help.

—P

Ernie Miller

unread,
Jul 2, 2010, 9:21:36 AM7/2/10
to rubyonra...@googlegroups.com

On Jul 2, 2010, at 9:11 AM, Paul Campbell wrote:

defining an attribute based on a Ruby keyword (private).

I'm pretty sure this isn't the case, since there's no "private" method
name. Interestingly, it's very difficult to come up for a name in this
that isn't a potential collision.

"private" and "public" being the most obvious choices, even
"anonymous" doesn't really work.

Anyway, thanks for your help.

—P

I haven't taken a look at the devise code, just wondered if perhaps a bareword public was being interpreted somewhere as a call to your scope instead in the context of a singleton_class eval.

Ernie Miller

unread,
Jul 2, 2010, 9:34:54 AM7/2/10
to rubyonra...@googlegroups.com

On Jul 2, 2010, at 9:11 AM, Paul Campbell wrote:
>
>> defining an attribute based on a Ruby keyword (private).
>
> I'm pretty sure this isn't the case, since there's no "private" method
> name. Interestingly, it's very difficult to come up for a name in this
> that isn't a potential collision.

I misspoke re "private" vs "public". I'm now on my second cup of coffee so fully qualified to respond. :)

I think this test lends credence to my suspicion, though:

ruby-1.9.2-head > class Tester
ruby-1.9.2-head ?> def self.public
ruby-1.9.2-head ?> puts "Hey, I'm not a keyword, I'm a class method!"
ruby-1.9.2-head ?> end
ruby-1.9.2-head ?> end
=> nil
ruby-1.9.2-head > Tester.instance_eval do
ruby-1.9.2-head > public
ruby-1.9.2-head ?> def blah
ruby-1.9.2-head ?> puts "blah"
ruby-1.9.2-head ?> end
ruby-1.9.2-head ?> end
Hey, I'm not a keyword, I'm a class method!
=> nil

Try renaming your scope and see if the issue persists.

Paul Campbell

unread,
Jul 2, 2010, 10:03:21 AM7/2/10
to rubyonra...@googlegroups.com
> ruby-1.9.2-head > Tester.instance_eval do
> ruby-1.9.2-head >     public
> ruby-1.9.2-head ?>  def blah
> ruby-1.9.2-head ?>    puts "blah"
> ruby-1.9.2-head ?>    end
> ruby-1.9.2-head ?>  end
> Hey, I'm not a keyword, I'm a class method!
>  => nil
>
> Try renaming your scope and see if the issue persists.

I had tried that, it did persist : José assures me he's fixed the
issue in Rails edge
(http://github.com/plataformatec/devise/issues/issue/357/#comment_296820),
so I'm switching to that!

—P

Reply all
Reply to author
Forward
0 new messages