I am using Rails' generators to produce things like models in my app.
My models are commonly using the class_name option on relations.
Is it possible to generate a model from the command line and pass the value for class_name? I specifically want to avoid modifying the model after the generator runs.
An example of what I hope exists is something like:
rails generate model Book title:string author:belongs_to{class_name:User}
Then the generated Book model would look like:
class Book < ActiveRecord::Base
belongs_to :author, class_name: 'User'
end
No, you can't pass class_name as an option to the generator. It is not a valid option to the generator command. You can see the list of available options by running
rails g model --help
I believe the only way is to manually edit the models to specify the class_name
Related
I am writing a gem for automatic scope generation (see AssociationScope).
I already did much work and currently I am working on scoped associations.
Rails Guide mentions how to write scoped associations, but not how to generally use them.
When I have the example from Rails Guide
class Book < ApplicationRecord
belongs_to :author, -> { where active: true }
end
I can use Book.reflections["author"] to see all relevant information for that association. With Book.reflections["author"].scope I get
#<Proc:0x0000560511e55d28 /home/datae/.rvm/gems/ruby-3.0.2/gems/activerecord-6.1.3.1/lib/active_record/associations/builder/association.rb:54>
I want to automatically generated a scope based on this association.
How can I use this Proc?
Steps to recreate application:
rails g model Book author:references
rails g model Author active:boolean
rails db:migrate
replace the generated Book class with the above code from Rails Guide.
I am running Ruby 2.1.9 and Rails 3.2.17.
First off, in Rails I always made the assumption that models should almost always be singular. I have seen model names like product_categories_product. This is fine and in habtm situation where you want a model to work with the relationship I have seen instructions_products. Which in Rails sorta may make sense, but I would rather name the model instruction_product. That was associated with a joins table named instructions_products.
In fact I was so frustrated I started looking at how rails names things and this happened? So clearly its an ok name for the model and would correspond to the correct table name. But what is more approriate?
ActiveModel::Naming.singular(InstructionsProducts)
returns instructions_products
Edited: The heart of the question is why is InstructionsProducts a valid model name in rails and why does my example above resolve to the singular 'instructions_products'. This seems odd considering the rails convention is to keep model names singular.
Your question is not completely clear to me.
By Rails conventions, model names are singular and written in camel case, for instance InstructionProduct. Each model matches a table in the database with the same words, down-cased, separated by '_' and in plural. instruction_products for the provided example.
Look at the following example using has_many:
class User < ActiveRecord::Base
has_many :contacts
end
class Contact < ActiveRecord::Base
belong_to :name
end
user = User.find(1)
user.contacts # returns an array of all the associated objects
When doing user.contacts, contacts is not the table name. It's the collection method, a placeholder for the symbol passed in the has_many method (please follow the has_many link and read what documentation says about has_many). Another name could be used, though:
class User < ActiveRecord::Base
has_many :personal_contacts, class_name: 'Contact' #, foreign_key: :contact_id
end
user = User.find(1)
user.personal_contacts
The class_name and foreign_key are required because rails conventions are not being followed. When using has_many :personal_contacts rails expects that personal_contacts will return an array of PersonalContact.
In Ruby you must start a class name with a capital word, so it is not possible to create a class named instruction_product. If you want to provide a name that does not follow the Rails convention, which I don't recommend, you will need to inform rails about the new table name:
Class AdminUser
self.table_name = "users"
end
Update 1:
As you already know, the convention states that the model should be declared as singular (class InstructionProduct instead class InstructionsProducts. However its just a convention. When a class inherits from ActiveRecord::Base, and a sql query is generated, ActiveRecord lowercases the class name, separates the words by _, converts to a plural name and uses it as the table name (mainly rails uses InstructionsProducts.model_name.plural which returns instructions_products).
You are assuming that singular actually does a name translation to singular, even if it's written in plural, but it doesn't. It assumes that you are using the convention, and mainly returns the class name underscored.
Looking at the rails source code (ActiveModel::Name), ActiveSupport::Inflector.underscore seems to be used (I just did a very superficial investigation, I have to admit). You can see how underscore works at documentation.
I have run
rails generate Model Profile name:string
It have worked and generated all the files.
When I see the profile.rb file though it only has the class declaration not the fields.
class Profile < ActiveRecord::Base
end
Do I have to add all the fields manually ?
No, you don't to add fields manually. ActiveRecord will discover them at runtime from the table structure. This is part of rails magic :)
I have tables already created from a different project. Their names are formatted like aaa_bbb_ccc_ddd (all non plural and some parts aren't a convention word). I have successfully created a schema from the database by reading this. But now I have to make the actual models. I've looked at RMRE, but they enforce the ActiveRecord convention on my tables and change their names, which I don't want to do because other apps depend on those tables.
What is the best way to automatically create models and a schema from existing tables?
just a theory, not sure how this would work in real app:
create models named as ActiveRecord convention requires, for example for table aaa_bbb_ccc_ddd you'll create a model AaaBbb and map this model to your table:
class AaaBbb < ActiveRecord::Base
self.table_name = "aaa_bbb_ccc_ddd"
end
or a more human example:
class AdminUser < ActiveRecord::Base
self.table_name = "my_wonderfull_admin_users"
end
Now you'll have AaaBbb as resource in routes meaning you'll have a url like:
.../aaa_bbb/...
and if you want to use the table name name in url I guess you could rewrite the route:
get 'aaa_bbb_ccc_ddd/:id', "aaa_bbb#show", as: "aaa_bbb"
again, just a theory that might help you out. I haven't worked with such cases yet but would've start from this.
edit
to automate model creation from database:
https://github.com/bosko/rmre
but I think this will create models by rails convention with wierd names that you'll have to use as resource in your app.
A good template that I found on SO in case you want to use a model name different from table name:
class YourIdealModelName < ActiveRecord::Base
self.table_name = 'actual_table_name'
self.primary_key = 'ID'
belongs_to :other_ideal_model,
:foreign_key => 'foreign_key_on_other_table'
has_many :some_other_ideal_models,
:foreign_key => 'foreign_key_on_this_table',
:primary_key => 'primary_key_on_other_table'
end
Just switch from Rails to Django and make
your life happier and also make your work normal:
$ python manage.py inspectdb my_table_without_existing_model > some_new_model.py
That's enough. Two seconds of work :)
I am a Java developer I've been learning Rails for the past few days. I have a Java EE application (Uses Hibernate for ORM) that I am trying to port to Rails. I have used scaffolding to generate a few of my models. But I have other models which contain references to other models. How do I define the relations? Can I scaffold that as well?
Here is an example for what I am trying to do.
public class Engine {
private int valves;
private int capacity;
private int rpm;
}
I can scaffold the Engine class in ruby just by doing the following:
rails generate scaffold Engine valves:integer capacity:integer rpm:integer
Here is the tricky part for me:
public class Car {
private Engine engine;
}
How do I scaffold the Car class in Ruby?
If I understand correctly you are looking for associations. Here's a great guide
that you should read. The thing to understand here is that you define in your models how the they relate to each other with a series of methods described in that guide.
Here is what I would suggest you do:
rails generate scaffold Car <db columns>
rails generate model Engine valves:integer capacity:integer rpm:integer car_id:integer
In your two models:
class Car < ActiveRecord::Base
has_one :engine
end
class Engine < ActiveRecord::Base
belongs_to :car
end
You can actually generate scaffold for both models...that will create controller and views. But in this case it might make sense to add
accepts_nested_attribues_for :engine
to your Car model instead. This will allow you to manage the manipulation of the Engine model from the controller and views of the Car model.
At any rate, I hope this helps you start to find what you need.
You can do it using the references helper of activerecord migration.
rails generate scaffold Car engine:references ...
it will add :
t.references :engine in your migration file
has_many :engines in your Car model file
belongs_to :car in your Engine model file
Don't forget to check the rails api for options (default, relation callbacks...)(here for exemple : http://railsapi.com/doc/rails-v3.0.8rc1/)
You should learn more about Ruby. Ruby is not a static language, meaning every variable can hold every kind of object.
The rails generate command uses valves:integer etc. only for database purposes, because databases need this information.
Concerning your relations problem you should read about has_many, bleongs_to etc. (see http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html) In Rails you would define your relation like this
class Car
belongs_to :engine
end
class Engine
has_many :cars
end
Furthermore you have to add a foreign key engine_id to Car.
This works because there are several conventions used in Rails.
Without a basic tutorial you will not get far.
There is no scaffolding for relations, you have to learn how to do it "by hand" (which is not too demanding). Have a look at the "Rails Guides", and here "Active Record Association".
In your example, you have to do the following steps:
Create a migration to migrate the database: rails g migration AddIds
Modify the migration to include the additional ID you have to have:
...
add_column :engines, :car_id, :integer
Add to you models the following code:
class Car
has_one :engine
...
end
class Engine
belongs_to :car
...
end