Reputation: 1209
I'm writing a little Ruby on Rails CMS, and I want to make a generator that would create models inheriting from the pre-built CMS data model. For example, I have a Entry
model in my CMS, and I want to create a Post
model that would be child of this model. This is the source code:
db/migrations/*create_mycms_entries.rb:
class CreateMyCmsEntries < ActiveRecord::Migration[5.0]
def change
create_table :my_cms_entries do |t|
t.string :type, index: true
t.string :title
t.string :slug, index: true
t.json :payload
t.integer :user_id, index: true
t.string :author_name
t.datetime :published_at
t.timestamps null: false
end
end
end
entry.rb:
module MyCms
class Entry < ActiveRecord::Base
scope :published, -> { where('published_at <= ?', Time.zone.now) }
def self.content_attr(attr_name, attr_type = :string)
content_attributes[attr_name] = attr_type
define_method(attr_name) do
self.payload ||= {}
self.payload[attr_name.to_s]
end
define_method('#{attr_name}='.to_sym) do |value|
self.payload ||= {}
self.payload[attr_name.to_s] = value
end
end
def self.content_attributes
@content_attributes ||= {}
end
end
end
and, at my blog side, post.rb:
class Post < MyCms::Entry
content_attrs :body, :text
# Rest of the stuff...
end
I want the final command look something like this:
$ rails generate entry Post body:text
But I'm not quite sure I know how to implement it.
Upvotes: 0
Views: 164
Reputation: 872
If you want to create custom model generator then you can use Thor (https://github.com/erikhuda/thor) which rails team has documented here
http://guides.rubyonrails.org/generators.html
First start by typing this command:
bin/rails g generator entry
So you are triggering generator to generate generator :). You will get something like this after running your command
create lib/generators/entry
create lib/generators/entry/entry_generator.rb
create lib/generators/entry/USAGE
create lib/generators/entry/templates
Then what you can do is just copy the code that ActiveRecord has for creating models. Inside your templates you will have this file model.rb like here
You will see that it has something like this:
class <%= class_name %> < <%= parent_class_name.classify %>
class_name is a variable that you pass to your generator, like in your example Post. And you can define it like this inside your entry_generator
argument :class_name, type: :string, default: "Post"
I would definitely recommend that you look at this file since the rails generator has everything you need...you would just customize it for your specific need:
In generator you have a class that invokes the template. Here is another video from Ryan Bytes that explains creating generator on custom layout which you can find it useful for your CMS.
http://railscasts.com/episodes/218-making-generators-in-rails-3?view=asciicast
Good luck
Upvotes: 1
Reputation: 5155
What you are trying to do is single-table inheritance (STI) and Rails has the support for that. Basically you need column type
in your entries
table which would store the class name within your hierarchy. You don't need to use the parent attribute as it seems to be in your example. See more in Rails docs or blogs, e.g. this one.
Upvotes: 1