-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
182 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,124 +1,186 @@ | ||
# Customization | ||
|
||
This engine allows us to do further development in Rails way from the following sections. | ||
Customization can be done in the following sections, and all examples will be based on Product model: | ||
|
||
First of all, let, if you have a model call `Product` and it has the following columns: | ||
- [Controller](#controller) | ||
- [Decorator](#decorator) | ||
- [Servicer](#servicer) | ||
- [View](#view) | ||
|
||
- sku:string | ||
- name:string | ||
- category_id:integer | ||
- description:text | ||
- stock:integer | ||
- price:float | ||
- featured:boolean | ||
- available_to_date:date | ||
- available_to_time:time | ||
- published_at:datetime | ||
> NOTE: model class is the only thing carried through a complete request. | ||
And it has model declaration as below: | ||
## Controller | ||
|
||
In order to customize a controller action, controller should inherit from `Wallaby::ResourcesController` as below, then we could override the general RESTful actions (index/show/new/create/edit/update/destroy): | ||
|
||
```ruby | ||
class Product < ActiveRecord::Base | ||
has_one :product_detail | ||
has_one :picture, as: :imageable | ||
has_many :order_items, class_name: Order::Item.name | ||
has_many :orders, through: :order_items | ||
belongs_to :category | ||
has_and_belongs_to_many :tags | ||
|
||
validates_presence_of :name, :sku | ||
#!app/controllers/products_controller.rb | ||
class ProductsController < Wallaby::ResourcesController | ||
def index; super; end | ||
def show; super; end | ||
def new; super; end | ||
|
||
# @example override create action | ||
def create | ||
flash[:notice] = 'Create product is in progress' | ||
super | ||
end | ||
|
||
def edit; super; end | ||
def update; super; end | ||
def destroy; super; end | ||
end | ||
``` | ||
|
||
## Configuration | ||
|
||
This engine by default uses ActiveRecord adaptor, you could change this to other adaptor (e.g. Mongo / HER adaptor) as below: | ||
If you have already declared a ProductsController for other purpose, you could use other controller name and specify the model class. | ||
|
||
```ruby | ||
# config/initializers/wallaby.rb | ||
Wallaby.config do |config| | ||
config.adaptor = Wallaby::SomeOtherAdaptor | ||
#!app/controllers/admin/products_controller.rb | ||
class Admin::ProductsController < Wallaby::ResourcesController | ||
def self.model_class | ||
Product | ||
end | ||
end | ||
``` | ||
|
||
By default, there is no authentication, and you need to do the following config if you need one: | ||
## Decorator | ||
|
||
If we need to change what fields to show, or update the metadata information of a field, we consider to use decorator. | ||
|
||
```ruby | ||
# config/initializers/wallaby.rb | ||
Wallaby.config do |config| | ||
config.security.authenticate do | ||
# you could use any controller methods here | ||
authenticate_or_request_with_http_basic do |username, password| | ||
username == 'too_simple' && password == 'too_naive' | ||
end | ||
end | ||
|
||
config.security.current_user do | ||
# you could use any controller methods here | ||
Class.new do | ||
def email | ||
'user@example.com' | ||
end | ||
end.new | ||
#!app/decorators/product_decorator.rb | ||
|
||
# NOTE: Product in ProductDecorator must be singular | ||
class ProductDecorator < Wallaby::ResourceDecorator | ||
# example of metadata: | ||
# { | ||
# column_name: { | ||
# type: string, | ||
# label: 'Column Name', | ||
# name: 'column_name' | ||
# } | ||
# } | ||
self.index_fields # metadata for index page | ||
self.show_fields # metadata for show page | ||
self.form_fields # metadata for new/create/edit/update page | ||
|
||
# example of field_names: | ||
# [ 'id', 'column1', ..., 'created_at', 'updated_at' ] | ||
self.index_field_names # array of column names to display on index page | ||
self.show_field_names # array of column names to display on show page | ||
self.form_field_names # array of column names to display on form page | ||
|
||
# examples | ||
self.index_fields[:email][:type] = 'email' | ||
self.index_fields[:full_product_name] = { type: 'string', label: 'Product Name' } | ||
self.index_field_names << 'full_product_name' | ||
|
||
def full_product_name | ||
[ product_name, sku ].compact.join ' - ' | ||
end | ||
end | ||
``` | ||
|
||
You could hide some models using configuration as below: | ||
Similarly, if ProductDecorator is taken, we could other name and specify the model class. | ||
|
||
```ruby | ||
# config/initializers/wallaby.rb | ||
Wallaby.config do |config| | ||
config.models.exclude ProductDetail, Order, Order::Item | ||
#!app/decorators/admin/product_decorator.rb | ||
class Admin::ProductDecorator < Wallaby::ResourceDecorator | ||
def self.model_class | ||
Product | ||
end | ||
end | ||
``` | ||
|
||
## Controller | ||
## Servicer | ||
|
||
You could modify the logics for Post model by defining a controller as below: | ||
If any actions need to be carried out in the persistence layer, we use a servicer (service object): | ||
|
||
```ruby | ||
class PostsController < Wallaby::ResourceController | ||
def create | ||
# do something else | ||
super | ||
#!app/servicers/product_servicer.rb | ||
class ProductServicer < Wallaby::ModelServicer | ||
# @return collection of resources | ||
def collection(params, ability); super; end | ||
|
||
# @return resource | ||
def new(params); super; end | ||
|
||
# @return resource | ||
def find(id, params); super; end | ||
|
||
# @example override create method | ||
# @return [ resource, boolean ] | ||
def create(params, ability) | ||
product, success = super | ||
publish_and_index product | ||
[ product, success ] | ||
end | ||
|
||
# @return [ resource, boolean ] | ||
def update(resource, params, ability); super; end | ||
|
||
# @return boolean | ||
def destroy(resource, params); super; end | ||
end | ||
``` | ||
# OR any controller name you want, but specifying the `model_class` | ||
class Admin::CustomPostsController < Wallaby::ResourceController | ||
def self.model_class | ||
Post | ||
end | ||
Similarly, if there is name conflict, just use other name and specify the model class. | ||
def create | ||
# do something else | ||
super | ||
```ruby | ||
#!app/servicers/admin/product_servicer.rb | ||
class Admin::ProductServicer < Wallaby::ModelServicer | ||
def self.model_class | ||
Product | ||
end | ||
end | ||
``` | ||
## Decorator | ||
## View | ||
It is easy to customize how a field should be rendered. In the following example, we will change product description to be rendered using markdown on index page: | ||
Similar to the controller above, you could use two ways to define a decorator. | ||
Having a decorator, you could then modify what fields to use for views index/show/form | ||
First of all, we need to update the type in decorator: | ||
```ruby | ||
class PostDecorator < ResourceDecorator | ||
index_field_names.delete 'body' | ||
show_fields['body'][:type] = 'markdown' | ||
form_fields['body'][:label] = 'Content' | ||
#!app/decorators/product_decorator.rb | ||
class ProductDecorator < Wallaby::ResourceDecorator | ||
self.index_fields[:description][:type] = 'markdown' | ||
end | ||
``` | ||
## View | ||
Then we need to add a partial for it. The partial can be either created under | ||
You could easily define any field view for any custom type (e.g. markdown) for Post by defining a partial under `app/views/posts/index/_markdown` | ||
``` | ||
#!app/views/products/index/_markdown.html.erb | ||
``` | ||
If it's product specific. Or | ||
``` | ||
#!app/views/wallaby/resources/index/_markdown.html.erb | ||
``` | ||
If it applies to all markdown fields. | ||
```erb | ||
<%# The local variables in the partial are `value` %> | ||
<%= markdown.render value %> | ||
<%= markdown.render value %> | ||
``` | ||
If you want to make it available for other models, you could move it to `app/views/resources/index/_markdown` | ||
### Index / show partials | ||
For index and show partial, we will have access to the following variables: | ||
- `object`: the resource object | ||
- `field_name`: current field name | ||
- `value`: current value | ||
- `metadata`: metadata for current field | ||
### Form partials | ||
For index and show partial, we will have access to the following variables: | ||
- `form`: the instance of Wallaby::FormBuilder providing additional helper methods for error class and error messages | ||
- `object`: the resource object | ||
- `field_name`: current field name | ||
- `value`: current value | ||
- `metadata`: metadata for current field |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.