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.
Related
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
Following to RailsGuides instruction, I have created an engine for blogging system in my app. This blog engine is mounted as /blog.
RailsGuides shows how to add belongs_to association to the mounted engine's Article model. However, the parent app's User model still requires has_many association to the engine's Article model which is in different namespace.
How to set has_many association between parent app's model and mounted engine's model?
Ruby 2.2.0
Rails 4.2.0
Thanks in advance.
In the rails application, you know what module you include, so you can simply specify the relation with the class name ;)
has_many :articles, class_name: 'Blog::Article'
check if this is the right syntax for your database adapter, e.g. I'm using this for Mongoid, but it should be the same with ActiveRecord AFAIK
The accepted answer requires manual modification of main_app's parent model in order to set the has_many relationships to the engine's child model. So each time you add the engine to one your main_apps you would have to go into the main_apps models and set up all required relationships by hand.
A more robust, although more complicated, solution would be to use the decorator pattern in the engine so that the engine will auto-configure main_app's parent model with the relationships it needs.
By using this method you just need to add a setting to the engine initializer in your main_app and the engine will handle the rest.
In engine:
blog.gemspec.rb
s.add_dependency 'decorators' #this will install the decorators gem for use in engine
lib/blog/blog.rb
module Blog
class Engine < ::Rails::Engine
isolate_namespace Blog
engine_name 'blog'
#to set up main_app objects via decorators in engine
config.to_prepare do
Decorators.register! Engine.root, Rails.root
end
end
end
lib/blog.rb
require 'decorators'
module Blog
mattr_accessor :user_class #Can now reference this setting as Blog.user_class
class << self
#the following lets us add functionality to main_app user model
def decorate_user_class!
Blog.user_class.class_eval do
has_many :articles, :class_name => "Blog::Article", :foreign_key => "user_id"
end
end
end
end
app/decorators/lib/blog/user_class_decorator.rb
if Blog.user_class
Blog.decorate_user_class!
else
raise "Blog.user_class must be set in main_app blog.rb initializer"
end
In main app:
app/initializers/blog.rb
Blog.user_class = User
If you run rails console from main app, you will see relationships will have been set properly. The decorator pattern in the engine can also be used to extend the main_app's models and controllers in different ways, not just Activerecord relationships. Almost complete decoupling achieved!
I am using the gem postmarkdown to create a blog in RoR. The Post model in the gem is not backed by a database (it uses ActiveModel). How would I go about relating a Comment model to the Post model for a blog that does not utilize a database for the blog posts?
For example, with a typical blog backed by an ActiveRecord database, I could set up the relations (such as)
class Post < ActiveRecord::Base
has_many :comments
However, in this case, I don't know the best way to create a comment model.
If Post is an activemodel, you can't setup relations using methods in activerecord. You can check out the README at github. It doesn't have that functionality.
One way you could to is simply define your own methods inside Post model.
class Post
def comments
Comment.where(:post_id => id)
end
end
class Comment < ActiveRecord::Base
def post
Post.find_by_id(post_id)
end
end
Edit:
Ah, I just find a similar question, Ruby on Rails 3 (3.1) ActiveModel Associations (tableless nested models). You can check out that as well.
I want to costumize the Model generator/scaffolder that is used by rails e.g.:
rails generate model ModelName field:field_tyle,...
rails generate scaffold ModelName field:field_type,...
to pretend some areas and it should look like this when Im done cosutumizing the template.
class ModelName < ActiveRecord::Base
# ASSOCIATIONS
# VALIDATIONS
# ATTR RELATED STUFF
# INSTANCE METHODS
# CLASS METHODS
end
instead of:
class ModelName < ActiveRecord::Base
end
It was easy to find the View Templates used by the scaffolder but its not that easy to find the template for the Model. Where can I find it or is there "only" a generator for this and when how can I costumize it?
there is a guide on customizing rails generators Rails Guides. File location you can check at Rails API just need to know class name also you can check nifty generators by Ryan Bates
I had a similar issue it took some doing but this work for me.
The ActiveRecord model generator templates for Rails 3.1 go in:
lib/templates/active_record/model/
This could be either model.rb, migration.rb or module.rb
I imagine that DataMapper or MongoMapper go in analogous locations. Hope this helps.
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