I want to create a model to manage blog posts and name it "post." Could this create a conflict with Rails built in methods?
The Rails Guide to Active Record Associations covers this issue:
3.2 Avoiding Name Collisions
You are not free to use just any name for your associations. Because
creating an association adds a method with that name to the model, it
is a bad idea to give an association a name that is already used for
an instance method of ActiveRecord::Base. The association method would
override the base method and break things. For instance, attributes or
connection are bad names for associations.
Figuring out whether your model name will cause a collision when it is used in an association is simple:
a = MyModel.new
a.respond_to?(:update) # => true
a.respond_to?(:post) # => false (assuming you haven't defined the association yet)
Edit:
I should probably point out that associations are not the only potential source of name collisions; in your case though it's pretty clear that update clashed with the :update method in ActiveRecord::Base.
Rails models are constants in the top-level namespace, so watch out for conflicts that arise from including library code.
Is it a bad idea to name a rails model “Post”
Yes. Your instincts are correct. Although not a reserved word, POST is a database action. Why not choose a name that has no opportunity to create confusion with the framework: Article, Comment...?
Related
I'm working through the Ruby on Rails tutorial and just made a Comment model with three properties.
rails generate model Comment commenter:string body:text post:references
It generated an ActiveRecord class with post but not commenter and body.
class Comment < ActiveRecord::Base
belongs_to :post
end
Why doesn't rails formally define the non-reference properties anywhere other than the DB migration scripts?
Rails dynamically loads attributes - specifically, the names of the columns and their types - based on the database schema. There is no need to define or declare them in your models. For apps running in production, it does this once, at load time. For development, it will reload them as often as every request, but only loads them when each model is used.
Rails does not infer other things from your database, though. For instance, if you were to place a unique index on a name column, it would not automatically add a validates_uniqueness_of :name to your model. Of course, the database would still enforce this constraint when you save the record, causing an exception to be raised should the name field contain a duplicate value. The recommendation, in this case, is to do both.
Why doesn't rails formally define the non-reference properties anywhere other than the DB migration scripts?
Well, where do you need them "defined" anyways? Migrations are the only place where these attributes matter coz its responsibility is to create database tables with those attributes.
If you do a scaffold on comments with similar parameters, it would also generate the views and it would be using the attributes. They don't need to be "defined" as such anywhere else.
The short answer to your question is "no". Even the migration is not a definitive place to look as there might be many migrations related to a model.
However, you may have a look at the generated "db/schema.rb" which is an aggregation of all migrations. It contains the schema definition of all activerecord models. This maybe your best bet.
Additionally, you may want to use the https://github.com/ctran/annotate_models plugin that inserts a comment in your model to help you keep track of all your model's attributes.
In Ryan Bates's first episode on complex forms, he adds the following to a model:
# models/project.rb
has_many :tasks
def task_attributes=(task_attributes)
task_attributes.each do |attributes|
tasks.build(attributes)
end
end
I've never thought about this before, but how does the Project model know what "tasks" of which Project instance? Does that come from the has_many association? Is it like, when the project is running and I'm viewing a Project, that's the "active" object so project.rb knows which Project object we're referring to, so it knows that tasks is really some_current_project.tasks? (I'm obviously grasping at straws here.)
Also, if someone would point me to some reference that explains other questions like this one, I'd really appreciate it.
I hope my question is clear. Please ask for more clarification in comments if needed.
Please note: I know that Active Record handles CRUD actions and that objects correspond to rows in tables, etc. Those are just descriptions of what Active Record is. I'm looking for how it works when the project is running. I also now the constructs MVC, but I can't seem to find a detailed explanation of what information is sent where with respect to Rails.
(Not sure I fully understood your question, feel free to let me know if that's the case.)
A rails model is basically a ruby class that is persisted to a database. So it acts like a normal ruby object for the most part, with some database magic mixed in.
You tell rails which project instance to load (e.g. by providing an id), and it loads the data from the database.
Then, when you call project.tasks is when the magic happens: the Project model has no tasks method, so it will trigger ruby's method_missing method. This will then load the associated records into model instances and provide access to them via a rails object.
Since a project has many tasks, rails knows it should look into the tasks database and load the rows where project_id is equal to the project model's id attribute.
In short, ruby meta-programming and monkey patching possibilities make much of rails' magic possible.
(Edit for question on routing.)
When you want to edit project number 13, you go to a URL that looks something like www.mysite.com/projects/13/edit. If you look at routes.rb in your config directory, you'll see (in Rails3) resources :projects what Rails does is set up all sorts of paths for you. Behind the magic, the edit path looks like
get '/projects/:id/edit' => 'projects#edit'
This basically says "when a user wants to see www.mysite.com/projects/13/edit, send him to the edit action in the projects controller and set the id parameter to the value that's in that place.
Then in your controller, you'll load the appropriate project with
#project = Project.find(params[:id])
In a similar way, you could do this (this is an dumb example):
In routes.rb, put
get '/projects/:id/edit_name/:name' => 'projects#edit'
And then in you controller
#project = Project.find(params[:id])
#project.name = params[:name]
So rails basically uses magic to assign values in the URL to params you can work with in your controller. You can read more about routing here: http://guides.rubyonrails.org/routing.html
What is the deal with this? I'm working with a pre-existing that I did not do myself. Everything in the database is labeled in singular form. user, security, spec, etc. I guess the right way would be users, securities, specs. At least that's what ruby on rails try's to lookup when I generate a scaffold .
How do I specifically state to use user instead of users in the sql. I don't see anywhere in my project where it is looking up the sql. I mean if my model is user you would think it would try to lookup user. Instead of users.
Thanks for any help.
You need set_table_name :name_of_the_table in your model (source).
So:
class User < ActiveRecord::Base
set_table_name :user
end
The reason they use plural for the table and singular for the model is because an instance of the model represents one user, whereas the table contains all the users. It's just to make it more readable and logical.
You can specifiy the table name:
How do I explicitly specify a Model's table-name mapping in Rails?
I have a Rails app with a few model classes (e.g. Category, Subcategory, User, etc.). In order to implement a not-too-trivial filter functionality, I built a hierarchy of filter classes: FilterCategory, FilterSubcategory, etc., that derive from FilterBase. Each of them uses the appropriate "sister" model class (e.g. Category.find :all).
I quickly realized that I can't simply call the "sister" model class without using "require" first. However, I now suspect that using "require" is the main reason for two other problems I posted here and here, which probably mess up the class caching when config.cache_classes=false.
Is there another way for me to call these other models without requiring them?
I tried using the BaseWithoutTable plugin, but when I call the "sister model", I end up getting "Not a valid constant descriptor: nil", which occurs since Rails looks for "FilterCategory::Category" rather than "Category".
Any thoughts of the best way to do that?
I'm using Rails 2.3.8, Ruby 1.8.7.
Thanks,
Amit
I wonder if you want ::Category - getting Category from the top-level namespace rather than scoping it to FilterCategory?
If your models are in the app/models directory, you shouldn't need to explicitly require them - Rails already takes care of that.
I have a simple has_one/belongs_to relationship between two models.
This is a new association in my application so there are many records that do not yet have the associated record created.
Throughout my application I'm assuming the model has the association and I'm accessing its attributes and methods. However, because the association doesn't exist, I'm running into a lot of errors.
What I would like to do is unobtrusively build the associated record on the fly whenever it's access for the first time through any of its methods and attributes. It does not matter that there is data in record, I simply need it to exist so those methods I'm calling can build the data.
Edit: I do not want to check and create the record on all of the instances where I'm trying to access the relationship, so idealy this needs to be done on the model itself and not in my controllers anywhere.
Any thoughts?
Thanks!
Here's what we ended up with that did the trick. I didn't write it (a co-worker did) but it passes the previously failing tests that I wrote for this case.
def stats_with_create
stats_without_create || create_stats
end
alias_method_chain :stats, :create
In the controller, you could put something like this in the show method (untested, but it should give you an idea:
#thing = Thing.find params[:id]
if #thing.other_thing.nil?
#thing.other_thing = OtherThing.new.save!
#thing.save!
end
This isn't ideal, and you could probably clean it up a lot by putting a method in the Thing model that would check for and create the related model instead of putting it into your controller.
Another option would be to create a new accessor that you use to access the other_thing, creating it as required.
However, the correct thing to do is probably to fix your data, either in a migration or directly, creating the related models properly.
The direct answer is to override method for the relationship. When called it will check if the record exists and create it if it doesn't.
However, I would recommend that you use a migration to create all of the records up front.
I have done this type of thing before but not on the model level. Ive done it on the controller level with a before_filter that ran before all methods which needed to access the model association that did or did not exist yet.
I just realized there is the after_find and after_initialize callbacks that you can use in the model.
You could stick:
def after_initialize
association.build if association.nil?
end
in your model and it should solve your problems.. (disclaimer: untested by me) :)