I seem to recall that there was a plugin or Rake snippet that would put comments in various Model classes after running a migration? It's a chore to have to look at db/migrate/X when I want to see which fields a given model has.
If not, I'll write one, of course. :)
There is a school of thought that suggests you you shouldn't put attribute comments in the model as it breaks the principal of DRY. I won't argue the point. However, one real nice way of identifying attributes of the model is to simply type the Model name when you are in ./script/console
> User
=> User(id: integer, loginname: string, password: string, fullname: string, created_at: datetime, updated_at: datetime)
I always have ./script/console session open when developing Rails.
You may be thinking of the Annotate Models plugin at:
http://repo.pragprog.com/svn/Public/plugins/annotate_models/
I believe that does exactly what you describe, although I haven't personally used it in a while, so can't vouch for its behaviour on more recent Rails versions.
Regards,
NeilS.
I maintain the annotate gem (which started life as that venerable plugin by Dave Thomas) and the latest version allows you to run
rails g annotate_models:install
which adds a rake file to your project. Afterwards, annotate will be executed whenever you run rake db:migrate (but only in development mode).
...currently this feature seems to be broken :-(
Related
I updated my Rails application to a newer version of Rails, and now one of my models is unusable, as if it was loaded empty, as if Rails was not aware of its structure and how to populate it.
This model is Task and is based on Single Table Inheritance:
class Activity < ActiveRecord::Base
(...)
end
class Task < Activity
(...)
end
class Event < Activity
(...)
end
class Phase < Activity
(...)
end
Here is what is expected when the model is loaded properly and everything works well (same model because of STI):
Activity.inspect => Activity(id: integer, type: string, project_id: integer, author_id: integer, subject: text, description: text, (...), created_at: datetime, updated_at: datetime)
Task.inspect => Task(id: integer, type: string, project_id: integer, author_id: integer, subject: text, description: text, (...), created_at: datetime, updated_at: datetime)
Event.inspect => Event(same model as above ...)
(...)
However, since the update, Rails is unable to use the Task model at all, neither for reading a record from the database or creating a new one. Other related models Event and Phase works as expected.
When I debug it in production mode by inspecting the Task class and Task.first from the Task controller # show I get:
Task.inspect => Task()
Task.first.inspect => #<Task >
Task.first.nil? => false
This model appears as if it was void. Others models are loaded perfectly.
The application does not fail with an error when Rails tries to load the record, but it fails later when the controller tries to access any field, because the model is empty.
Some important observations :
It only fails in production mode, but works well in development mode, or it fails only when config.cache_classes = true but works well otherwise.
It works well in the Rails console.
task.rb model file gets loaded even in the failing context. Model files structure is flat, all models are in app/models/
It used to work well before updating from Ruby 1.9.3 and Rails 3.1 to Ruby 2.3.8 and Rails 3.2.22.
This is probably a duplicate of https://stackoverflow.com/a/58867450/1388302
Something else is defining Task - maybe to extend it. Don't do that. Use prepend. Otherwise the autoloader finds that unintentional definition and won't load the one you intend.
Or Task is now also defined by something you're including. It might be interesting to ask about Task.superclass.
This probably came up because Rails 6 changed the autoloader.
Something looks buggy with respect to Rails 3.2.22 schema loading and STI.
The best workaround I found so far is to force schema reloading for this model using :
Task.connection.schema_cache.clear!
Task.reset_column_information
But then Rails looses track of STI and will miss adding the "type" field to the newly created records. So to force this fields, in every controller required, I added :
#task = (...).becomes(Task)
This feels hacky, but I could not find any better way. Maybe this tip will help someone else. In my case it was not an option to upgrade Rails further or to refactor all the code to get rid of STI.
I've started learning Ruby last week, and I've started learning Rails today, so bear with me.
I see that Rails come with generators that allow you to generate models/controllers or even model+controller+views bundle as 'scaffold'. This is what I am interested in.
However, I have a question. How do I set database options of the column?
eg. To generate a users table I would do:
rails g scaffold users uuid:binary name:string email:string password:binary registered_on:date number:integer default:string
Now what if I'm integrity freak and am not happy by having validation just in model/controller, but want to do database level limitations as well.
What if I want email to be 50 characters max, and number to Auto-Increment and neither of all fields is allowed to be NULL and default field must have a default of 'foo'. Is there any way to pass these requirements to generator command?
I know its possible to set these options in .rb file that is used in rake db:migrate, however it would be easier to just pass values in with 1 command.
At least some things are available, like string length, but not sure about the others.
rails g scaffold users email:string{50}
Use type modifiers between curly braces, example:
rails generate migration AddDetailsToProducts price:decimal{5,2}
More info: migrations
Use scaffold and obtain generic migration files. And, as you mentioned, do the customizations in there. This files are found in db/migrate.
After you are done customizing the fields, don't forget to do a rake db:migrate.
I made a standard Active::Record class with a user_id field on it, and sure enough, the requirements changed. Turns out I needed to nix the 'user_id' column, and put on an 'email' column instead. I figured I would just manually replace the field in the migration file and then do a quick 'rake db:migrate down/up' on that version to make the update. I even ended up updating db/schema.rb as well.
No Dice:
Failure/Error: ss = Factory(:model)
undefined method `email=' for #<Model:0xb2cc288>
I can use email getter/setter methods in the console, or in the service fine -- but factory girl doesn't seem to get the hint. Is it caching a method list somewhere? (Hint: mysql table looks good too)
Firstly, in the future, try really hard not to change existing migration files. You will mess up more than just FactoryGirl, namely you will mess up your teammates' setups. Requirements change and that's OK, you just make a new migration that drops the user_id column and adds an e-mail column. This way, the evolution of the data model will be recorded in the migrations.
For your specific problem, though, you probably want to run rake db:test:prepare or, if that doesn't work, drop your test database completely and rebuild it.
i have this crazy label for each time i create a migration that use the time instead of a integer. it makes things very hard to switch between the version of the database that you want to use.
i also have this crazy ID for each object that i create :
http://poocs.net/", created_at: "2010-03-17 23:02:17", updated_at: "2010-03-17 23:02:17">
How can set up rails to have easy version and id numbers.
thank you
The number is timestamp. Really useful when you have several collaboration in same project.
If you want the old system us that in your environement.rb file
config.active_record.timestamped_migrations = false
Why would you need to switch between "versions of the database"?
If you mean redoing and undoing a migration, you can do it like this:
rake db:rollback
Which undoes the last migration, then
rake db:migrate
To redo it again. You shouldn't need anything else, since migrations should always be done sequentially in the timestamped order.
I am using NetBeans to create my first Ruby on Rails application. Is there a way by which I can view all of the properties of a model? Should I just be looking in the database?
I just use db/schema.rb - seems to work fine for me.
You can use the annotate gem for this - it will add comments to the top of each model indicating its properties.
You could call Model.attributes in Rails' console. This gives a hash with all attributes.
Be careful when using this inside your real code as it always recreates the hash and is therefore pretty expensive.
Just type your model name on the rails console then press Enter.
rails c # start your rails console
User
=> User(id: integer, email: string, password_digest: string...)
In case anyone is viewing this and is using a newer version of Rails, you can just call Model in the console. (I'm on Rails 3.2.1 and Ruby 1.9.2p290.)
In fact, calling Model.attributes in this case does not work.
A nice little tool that I use is from MySQL. It is called MySQL Administrator.
It lets me validate that the db (development/test/production), the tables for the db, and finally the columns(attributes).
Model.attributes #=> {'name' => 'foo', 'desc' => 'bar'}
P.S. www.railsbrain.com - use this.