ActiveLeonardo let you create a management application from scratch in few minutes.
The generator is not intended to churn out the finished product but provides a basis from which to start. It creates the skeleton of the application which will cut out a dress and as we know a nice dress should be tailored by hand.
The achievement is remarkable and I recommend you give it a try.
The generator is not intended to churn out the finished product but provides a basis from which to start. It creates the skeleton of the application which will cut out a dress and as we know a nice dress should be tailored by hand.
The achievement is remarkable and I recommend you give it a try.
On github there is a short tutorial and here I show you a more descriptive guide to clarify its potential.
I can summarize with this three simple steps:
- Create the new app
- Adding resources (information to manage)
- Starting the web server, the end!
You choose the name, you define the resources, all the remnant is a load of your PC.
My Windows 7 laptop with a second generation i7 and a 7200 rpm hard use about 1 minute. With a desktop and a SSD the operation is almost instantaneous. In any case the generator will create all the necessary in very little time and with minimum effort.
I will create a container of information in this case a rudimentary issue tracker (but could also be a recipe book, a blog, etc..) So we start by creating the application LeoTicket:
rails new LeoTicket -m dl.dropbox.com/u/52600966/active_template.rb
To accept the proposed sections just answer y. I suggest you add everything to better follow this tutorial.
The template allows you to add some basic gem for handling authentication, the permissions, the states ... you can add everything you need.
If you include the authentication you can choose the name of the resource, the default user is used but you can replace it by any other name (eg Author) as long as you remember to specify it when you create the following resources to allow the generator successfully compile the file permissions. To do this you need to pass the parameter to the generator of the resource, for example:
If you include the authentication you can choose the name of the resource, the default user is used but you can replace it by any other name (eg Author) as long as you remember to specify it when you create the following resources to allow the generator successfully compile the file permissions. To do this you need to pass the parameter to the generator of the resource, for example:
rails g leosca category name --auth_class=Author
The generator leolay replaces the original file en.yml (initially empty) with his custom, answer y to overwrite it. It is not done automatically if it is not the first generation (eg to update the generator), in this case we have to manually manage the conflicts.
At this point the application is already running and we can verify this by entering the directory of the new application and starting the server:
rails s
Open your web browser and go to the address:
http://localhost:3000/
You will be prompted to authenticate, insert:
admin@leoticket.com
abcd1234
And you will be redirected to the dashboard:
It has been already created the management of the users and this is the starting point for developing the application.. We provide resources thus creating two category:
In the REST architecture, a resource is largely attributable to a table on a database.
rails g leosca category name
Since Rails 3.2, the fields are considered as string if type is omitted so that is no longer necessary to specify it.
and now we can add the resource ticket:
rails g leosca ticket category:references title description:text state:integer
category:references tells to Rails to create an association with that resource: it creates a foreign key category_id and an index that uses to manage the relationship, in the ticket model there will be:
belongs_to :category
means that the ticket can query its category but not vice versa, if we want to query all the ticket you need to enter in the template category:
has_many :tickets
Let's go back to the project and check the result but first we have to apply to the db in that the generator has created for us:
rake db:migrate
== CreateCategories: migrating =============================================== -- create_table(:categories) -> 0.1430s == CreateCategories: migrated (0.1440s) ====================================== == CreateTickets: migrating ================================================== -- create_table(:tickets) -> 0.0040s -- add_index(:tickets, :category_id) -> 0.0010s == CreateTickets: migrated (0.0070s) =========================================
in order to facilitate the development stage, are generated generic records that you may also update before insert in the db to create more real cases:
#db/seeds.rb
[
{ :id => 1, :name => "Bug" },
{ :id => 2, :name => "Update" },
{ :id => 3, :name => "Implementation" },
].each do |fields|
category = Category.new fields
category.id = fields[:id]
category.save
end
Ticket.create([
{ :category_id => 1, :title => "New bug", :description => "I had a bug, damn!", :state => 10 },
{ :category_id => 2, :title => "Change this section", :description => "I require a change", :state => 10 },
{ :category_id => 3, :title => "New section", :description => "I need a new resource to manage ...", :state => 10 },
])
We want the id of the category is fixed and does not automatically attributed so we specify it and add it to the db with an alternative way to what is proposed by the generator. I do not know if there is a better way to do it.
Before proceeding we add the attribute category_id to the list of accessible attributes:
#app/models/ticket.rb class Ticket < ActiveRecord::Base belongs_to :category attr_accessible :description, :state, :title, :category_id end
And now we add these records to the database:
rake db:seed
If you receive the following error:
rake aborted!
Can't mass-assign protected attributes: category_id
You have not added category_id to the list of accessible attributes.
If you receive a "primary key violation" error:
rake aborted!
SQLite3::ConstraintException: PRIMARY KEY must be unique
You're probably running the import again, comments the categories in the file seeds.rb
You can run it multiple times to add more records.
The test application is ready, restart the server and update the browser:
rails s
http://localhost:3000/
Easy, not it?
- Developing localization
- Customize permissions
- Customize activeadmin views
- Develop models
- Create any alternative frontend
Localization
The application comes localized in English (default) and Italian (but you can extend the generator pretty easily) and just change the tags within files config/locales/*.yml
Customize permissions
Using cancan, edit the permissions is very simple, it is all contained within the file app/models/ability.rbCustomize views
Also Active Admin customizations are very simple. Everything is concentrated in the file relative to resource: list, consultation, form data, exports etc..
Each file is located in the folder app/admin/*.rb
Each file is located in the folder app/admin/*.rb
We can customize many things:
ActiveAdmin.register Ticket do menu :if => proc{ can?(:read, Ticket) } #change the default sort config.sort_order = 'id_asc' #add scopes: lists with preset filters scope :open scope :closed controller do load_resource :except => :index authorize_resource end #choose the column in the list index do id_column column :category column :title column :description column I18n.t('attributes.ticket.state'), :sortable => :state do |ticket| span ticket.human_state_name.capitalize, :class => "status #{ticket.state_name}" end default_actions end #...in the show show do |ticket| attributes_table do row :category row :title row :description row I18n.t('attributes.ticket.state') do span ticket.human_state_name.capitalize, :class => "status #{ticket.state_name}" end end end #...the form form do |f| f.inputs do f.input :category f.input :title f.input :description f.input :state, :as => :select, :collection => Ticket.state_machine.states.map{|s|[s.human_name.capitalize, s.value]}, :include_blank => false end f.buttons end #...and customize the export csv do column I18n.t('models.category') do |ticket| ticket.category.try(:name) end column :title column :description column I18n.t('attributes.ticket.state') do |ticket| ticket.human_state_name.capitalize end column(I18n.t('attributes.created_at')) { |user| user.created_at.strftime("%d/%m/%Y") } column(I18n.t('attributes.updated_at')) { |user| user.updated_at.strftime("%d/%m/%Y") } end end...and many other things for which I refer you to the official documentation of ActiveAdmin.
Pay attention to load related resources! (eager loading)
In rails is automatic but if it is not indicated to load them in advance, they will be retrieved when needed.
If we check in log / development.log will notice three individual queries to the archive of the categories, one for each ticket for which you show the name:
[1m [36mCategory Load (1.0ms) [0m [1mSELECT "categories".* FROM "categories" WHERE "categories"."id" = 1 LIMIT 1 [0m [1m [35mCategory Load (1.0ms) [0m SELECT "categories".* FROM "categories" WHERE "categories"."id" = 2 LIMIT 1 [1m [36mCategory Load (1.0ms) [0m [1mSELECT "categories".* FROM "categories" WHERE "categories"."id" = 3 LIMIT 1 [0m
For small lists is not a big problem but instead it is for large amounts of data, such as extractions csv format, so you need a little change on the controller. ActiveAdmin relies on Inherited Resources and you must act in this way:
ActiveAdmin.register Ticket do #...[CUT]... controller do load_resource :except => :index authorize_resource def index super do |format| format.html { @tickets = @tickets.includes(:category) } format.csv { @tickets = @tickets.includes(:category) } end end end #...[CUT]... end
If you now check the log again you find a single query:
[1m [36mCategory Load (0.0ms) [0m [1mSELECT "categories".* FROM "categories" WHERE "categories"."id" IN (1, 2, 3) [0m
Develop models
Models management is also very simple. We modify the related files in app / models / *. Rb adding validations, scopes, state management, etc..
class Ticket < ActiveRecord::Base belongs_to :category attr_accessible :description, :state, :title, :category_id state_machine :state, :initial => :new do state :new, :value => 10 state :working, :value => 20 state :canceled, :value => 30 state :completed, :value => 40 end OPEN_STATES = [state_machine.states[:new].value, state_machine.states[:working].value] CLOSED_STATES = [state_machine.states[:canceled].value, state_machine.states[:completed].value] validates :state, :inclusion => { :in => state_machine.states.map(&:value), :message => "%{value} is not a valid value! Available states: #{state_machine.states.map(&:value).compact.join(', ')}" }, :allow_nil => true scope :open, where(:state => OPEN_STATES) scope :closed, where(:state => CLOSED_STATES) endAnd here is the customized version:
Visualizzazione |
Form dati |
Lista |
For the moment thats all
If you like this article take a look at my sponsors, thank you!