- Binda
- Quick Start
- Installation
- Settings
- => return string which can be ‘true’ or ‘false’
- => return string with website name
- => return text with website description
- Structures
- get all field groups:
- get all field settings:
- (loop method) (returns an Array object)
- (single query method) (returns an ActiveRelation object)
- if structure is a component type
- if structure is a board type
- Get the field group
- Get the structure
- Components
- return all pages
- return my-first-page
- expand query
- reduce N+1 query issue by including dependencies
- SLOW
- FASTER
- which is the same thing of doing:
- which is the same thing of doing:
- your application single animal route
- the bound to a animal preview should be
- Boards
- return the board
- reduce N+1 query issue by including dependencies
- Fields
- Create a field setting
- => Binda::FieldSetting id: 1, ...
- You don’t have to create a text field for each component, it’s alreay been done for you
- WARNING! You won’t find immediately the text record associated, you need to reload!
- => nil
- => Binda::Text id: 1, field_setting_id: 1, ...
- controller file
- view file
- => ‘Hello world’
- returns all artists which are related to at least one event
- returns all events which are related to at least one artist
- Repeaters
- Users
- Maintenance Mode
- config/routes.rb
- config/routes.rb
- app/controllers/application_controller.rb
- Field settings and field groups
- Plugins
- Upgrade from a previous version
- Create a Binda plugin
- binda_new_feature.gemspec
- Maintain your gem’s version:
- Describe your gem and declare its dependencies:
- lib/binda_new_feature/engine.rb
- require File.expand_path(‘../../config/environment’, FILE)
- should be changed to
- spec/controllers/binda/foo_controller_spec.rb
- config/routes.rb
- lib/binda_new_feature/engine.rb
- … all require gems
- How to create a form of nested components
- controller
- Let’s say your structure has slug = my_structure and id = 123
- and you want to edit component_A and its child component_B
- or if you use Friendly_id
- view
- How to contribute
- Binda versioning
Binda
A modular CMS for Ruby on Rails 5.1.
This documentation has been written for the Official Documentation, not the Github README. If you still prefer to read Github README be aware that links might not work properly.
Quick Start
Binda is a headless CMS with an intuitive out-of-the-box interface which makes very easy creating application infrastructures.
The core element is the structure element which is the finger print of any component instance. Every structure can have one or more field-groups which can be populated with several field-settings. Field-groups and field-settings represent components features, such as galleries, textareas, dates, repeaters and so on.
Let’s say your website needs a set of pages with a subtitle. That’s super easy.
- create a “Page” structure
- go to General Details of “Page” structure (see the small pencil icon)
- set a “Description” field-settings based both on a String field type.
- set a “Featured Image” field-settings based both on a Image field type.
Done! Now you’ll see the “Pages” tab in your menu which will contain all your pages and where you can set the description and the featured image.
It’s easier learning by doing than by reading. ;-) Watch the preview on Binda’s vimeo channel
Installation
Install Binda via terminal
“sh gem install binda
“
alternatively add the gem to your application’s Gemfile:
“by gem ‘binda’
“
Then execute:
“sh bundle install
“
Before completing the installation you need to setup the database. If you are going to use Postgres set it up now.
To complete binda installation run the installer from terminal. Binda will take you through a short configuration process where you will setup the first user and some basic details.
“sh rails generate binda:install
“
Now you are good to go. Good job!
Recommended workflow
Binda is totally bound to its database in order to let you structure your CMS directly from the admin panel. The recommended workflow is:
- Install and develop the application locally
- Migrate server and database to production once ready
- Restart after having synched the database. This ensure settings are cached correctly
- Rinse and repeat 😀
Reset initial settings
If you need to re-install Binda and reset initial database settings (such as username and password for example) execute the following command from the application root.
“sh rails generate binda:setup
“
Credentials
If you have lost your username/password you can run
“ails binda:create_superadmin_user
“
This lets you create another temporary super admin user.
Specific needs
In order to use Carrierwave to process images you need to run MiniMagik. Please refer to Carrierwave documentation to find more information.
If you need absolute URLs for your images remember to set up your asset host in config/environments/production.rb
“by Rails.application.configure do … config.action_controller.asset_host = ‘http://your.host.com’ … end
“
If you are not going to use Rails default ORM please check Carrierwave documentation and Devise documentation.
Settings
Binda comes with some default preferences.
During the installation process you will be asked to provide the website name, website description and the credentials for the default super administrator.
This two preferences can be changed later on inside Dashboard panel visible in the sidebar.
You can customize the Dashboard panel adding, removing and modifing fields as you prefer. As a matter of fact in Structures you can find the one related to Dashboard which you can edit as you like. The only thing you shouldn’t do is to turn it into a component!
You can also create new boards if you need it, you just have to create a structure and set it to board
via admin panel or assign instance_type: 'board'
to structure (your_structure.update_attribute('instance_type', 'board')
).
By default after the installation a Board
called dashboard
will be populated with three fields: a Radio
called maintenance-mode
, a String
called website-name
and Text
called webiste-description
.
You can retrieve them this way:
“by B.get_boards(‘dashboard’).first.get_radio_choice(‘maintenance-mode’)
=> return string which can be ‘true’ or ‘false’
B.get_boards(‘dashboard’).first.get_string(‘website-name’)
=> return string with website name
B.get_boards(‘dashboard’).first.get_text(‘website-description’)
=> return text with website description
“
Structures
Structures are the DNA of the application components and boards. Each component and board is defined by a structure.
Create a structure
Creating a structure is fairly easy. Just click on the sidebar tab called Structures and then on the New structure button. You will be asked to provide a name which will be used from then on to call the relative component or board. You can also select the type of structure: component or board. The former will let you create multiple instances for that structure whereas the latter will let you create only one instance. Why? A component is great for something like posts, pages and so on. Board are useful for content that is set once throghout the application, for example the website description.
Once the structure has been created it’s possible to add field groups. By default there is one field group called General Details which is empty. You can customize that or add new ones.
In order to add field settings that will let you add content to your component (or board) you need to enter on of the structure’s field groups.
Retrieve structure elements
Once you create a structure you can call it from your controller like so:
“by @my_structure = Binda::Structure.find_by(slug: ‘my-structure’)
“
From that you can do all sorts of things.
“by
get all field groups:
@field_groups = @my_structure.field_groups
get all field settings:
(loop method) (returns an Array object)
@field_settings = [] @field_groups.each do |group| group.field_settings.each do |setting| @field_settings « setting end end
(single query method) (returns an ActiveRelation object)
@field_settings = Binda::FieldSetting .includes(field_group: [:structure]) .where(binda_field_groups: @my_structure.id)
“
Depending on the structure type, to retrieve all related components or the related board you can use the Binda helper (which is suggested if you care about performance, see component or board) or do it the usual Ruby on Rails way like so:
“by
if structure is a component type
@components = @my_structure.components
if structure is a board type
@board = @my_structure.board
“
To retrieve field groups or a structure from a field setting you can do the following:
“by @field_setting = Binda::FieldSetting.find_by(slug: ‘my-field’)
Get the field group
@field_setting.field_group
Get the structure
@field_setting.structure
“
Note that @field_setting.structure
is a convenient method Binda offers to get the structure, but don’t over think: this doesn’t mean there is a association Binda::Structure --has_many--> Binda::FieldSetting
! The association is always mediated by Binda::FieldGroup
.
Components
Components are instances of a structure.
In order to retrieve a single component you can use one of the following methods:
Using the helper
A useful helper is B.get_components
. This helper will retrieve all components from a specific structure. Find specific info in the technical documentation.
Then in any of your controllers you can retrive the components belonging to a specific structure just using the structure slug. Let’s see an example that uses the page
structure to retrieve all related components.
“by B.get_components(‘page’)
return all pages
B.get_components(‘page’) .find_by(slug: ‘my-first-page’)
return my-first-page
expand query
B.get_components(‘page’) .published .order(‘position’)
reduce N+1 query issue by including dependencies
B.get_components(‘page’) .includes(:strings, :texts, repeaters: [:images, :selections])
“
To be able to use this helper in the application console you need to run Binda.include Bidna::DefaultHelpers
Using the rails way
Retrieve a single component
“by @component = Binda::Component.find_by( slug: ‘my-first-component’)
“
Retrieve a single component but eager load the field setting needed. This optimize the query and greatly reduce request time.
“by @component = Binda::Component.where(slug: ‘my-first-component’) .includes( :strings, :texts, :assets, :selections ) .first
“
Then, if you want to retrieve all components that belongs to a specific structure don’t do the following:
“by
SLOW
@structure = Binda::Structure.find_by( slug: ‘my-structure’) @components = @structure.components
“
Do this instead!
“by
FASTER
@components = Binda::Component.where( structure_id: Binda::Structure.where( slug: ‘my-structure’ ) )
which is the same thing of doing:
@components = B.get_components(‘my-structure’)
“
You can add any other option to the query then:
“by @components = Binda::Component.where( structure_id: Binda::Structure.where( slug: ‘my-structure’ ) ) .published .order(‘name’) .includes( :strings, :texts, :assets, :selections )
which is the same thing of doing:
@components = B.get_components(‘my-structure’) .published .order(‘name’) .includes( :strings, :texts, :assets, :selections )
“
Enable preview
When you created the component structure you might want to enable the preview mode. The easiest way to integrate the preview with yor application is to update the config/routes.rb
file with a redirect that binds the component preview url to the controller that is in chardge of showing that component in your application.
For example let’s say you have a animal structure with slug = animal
:
“by
your application single animal route
get ‘animals/:slug’, to: ‘animals#show’, as: animal
the bound to a animal preview should be
get “admin_panel/animal/:slug”, to: redirect(‘/animals/%slug’)
“
Boards
Boards give you the possibility to have a panel where to list some specific settings.
A great example of a board is the Dashboard. This board is useful to store the generic data which can be used throughout the application, like the website name and description.
You can create as many boards you like and add any field you want. To set up a board go to Structures and create a new structure with type “board”. The name of the structure will determine also the name of the board. Once created a new tab will appear on the main sidebar. The newly created structure is already populated with the General Details field group which is initially empty. To add new field settings you can decide to edit this field group or create a new field group.
Once ready you can head to the board page by clicking the tab on the main sidebar and populate the fields with your content.
To retrieve board content you can use one of those methods:
“by @board = Binda::Board.find_by(slug: ‘my_board’)
@board = B.get_boards(‘my-board’).first
“
Board Helpers
If you care about performance you can use the Binda.get_board
helper to retrieve the board object.
This method retrieves a board. Find specific info in the technical documentation.
“by B.get_boards(‘my-dashboard’).first
return the board
reduce N+1 query issue by including dependencies
B.get_boards(‘default-dashboard’) .includes(:strings, :texts, repeaters: [:images, :selections]) .first
“
Boards can make use of all field helpers. See the fields documentation for more information.
To be able to use this helper in the application console you need to run Binda.include Bidna::DefaultHelpers
Using console
If you are going to use Rails console you need to know that a board is automatically generated once you create a structure with an instance_type
of board
.
Example:
“sh board_structure = Binda::Structure.create!(name: ‘new dashboard’, instance_type: ‘board’) board = board_structure.board
“
Fields
Every field setting is based on a field type. You can create several field settings based on a single field type.
Here below a list of field types available and their use:
Field type | Usage | |
---|---|---|
string | Store a string. No formatting options available. | source |
text | Store a text. TinyMCE let’s you format the text as you like. | source |
image | Store image. | source |
svg | Store svg. | source |
video | Store video. | source |
audio | Store audio. | source |
date | Store a date. | source |
radio | Select one choice amongst a custom set. | source |
selection | Select one or more choices amongst a custom set. | source |
checkbox | Select one or more choices amongst a custom set. | source |
repeater | Store multiple instances of a field or a collection of fields. | source |
relation | Connect multiple instances of a component or board to each other. | source |
Available setting and customization
Sometime you might want to specify a behaviour or a restriction for a specific field. To konw more about a specific field click on the source link where you can find a more comprehensive documentation.
Reload!
In order to keep consistency between fields and their own settings Binda use callbacks.
For example the following line will create a field setting, but under the hood it provide each component with the relative field:
“by
Create a field setting
@structure.field_groups_first.field_settings.create(name: ‘my text’, field_type: ‘text’)
=> Binda::FieldSetting id: 1, ...
You don’t have to create a text field for each component, it’s alreay been done for you
WARNING! You won’t find immediately the text record associated, you need to reload!
@structure.components.first.texts.first
=> nil
@structure.reload.components.first.texts.first
=> Binda::Text id: 1, field_setting_id: 1, ...
“
IMPORTANT: Sometimes callbacks run and the ActiveRecord
object stored in your variable might get outdated. Use reload
to make sure the ActiveRecord
in your variable correspond to the real database record. (run mycomponent.reload
)
Some callbacks can a bit sneaky. For example field settings with field_type='radio'
cannot have allow_null=true
so no matter how many times you try to update allow_null=true
it will never change.
How to get field content
Every field setting has a unique slug
. The default slug
is made of the structure name + field group name + field setting name
. If it’s a child of a repeater the slug will include the repeater slug as well. You can customise the slug
as you like keeping in mind that there every slug
can be attach to only one field setting.
In order to retrieve a field content you can use one of the following helpers.
Let’s say you want to get a specific field from a component instance:
“by
controller file
@article = B.get_components(‘article’).first
view file
@article.get_text(‘description’)
=> ‘Hello world’
“
This helpers will work for any instance of Binda::Component
, Binda::Board
and Binda::Repeater
.
Field Helpers
Here below a list of helpers.
You can retrieve field content from a instance of Binda::Component
, Binda::Board
or Binda::Repeater
. See How to get field content.
NOTE: source links are based on the latest public version. If you are using an older version or a specific branch please refer to the source on github and switch to the branch/tag you are looking for.
| has_text
| Returns true/false
| source | | get_text
| Returns the text. Use simple_format
to maintain HTML tags. | source | | has_string
| Returns true/false
. | source | | get_string
| Returns the text. Use simple_format
to maintain HTML tags. | source | |has_image
| Returns true/false
.| source | |get_image_url(size)
| Returns the url of the image. A thumbnail version (200x200) by specifying thumb
size. If no size is provided the method will return the original image size. | source | |get_image_path(size)
| Returns the path of the image. A thumbnail version (200x200) by specifying thumb
size. If no size is provided the method will return the original image size. | source | |get_image_size
| Returns the image size in MB. | source | |get_image_dimension
| Returns a hash { width: xxx, height: xxx } with image dimension. | source | |get_image_mime_type
| Returns the mime type of the image. | source | |has_svg
| Returns true/false
.| source | |get_svg_url
| Returns the url of the svg. | source | |get_svg_path
| Returns the path of the svg. | source | |get_svg_size
| Returns the svg size in MB. | source | |get_svg_mime_type
| Returns the mime type of the svg. | source | |has_video
| Returns true/false
.| source| |get_video_url
| Returns the url of the video. | source | |get_video_path
| Returns the path of the video. | source | |has_audio
| Returns true/false
.| source | |get_audio_url
| Returns the url of the audio. | source | |get_audio_path
| Returns the path of the audio. | source | |has_date
| Returns true/false
| source | |get_date
| Returns the date in datetime
format. Use strftime
to change date format. | source | |has_repeaters
| Returns true/false
| source | |get_repeaters
| Returns an array of repeaters. See next session for more details. | source | |get_selection_choices
| Returns an hash with label and value of the selected choice. | source | |get_radio_choice
| Returns an hash with label and value of the selected choice. | source | |get_checkbox_choices
| Returns an array of label/value pairs of all the selected choices. | source | |has_related_components
| Check if has related components. | source | |get_related_components
| Retrieve related components. | source | |has_related_boards
| Check if has related boards. | source | |get_related_boards
| Retrieve related boards. | source |
If you need to get each dependent of all relations with a specified slug (or slugs) you can use B.get_relation_dependents
helper. This is very useful to retrieve only the instances which have a owner (and therefore are ‘dependents’).
For example, you have several event
components, each related to several artist
components with a partecipants
relation field where every event owns some artists. If you want to retrieve all artists which have been involved in at least one event you can try with
“by B.get_relation_dependents(‘partecipants’)
returns all artists which are related to at least one event
“
If you want to retrieve each owner of all relations with the specified slug (or slugs) you can do the following:
“by B.get_relation_owners(‘partecipants’)
returns all events which are related to at least one artist
“
Repeaters
Generally a field setting is associated to a single content entry. Therefore if a field setting has type text
there will be only one Binda::Text
related to it.
If you want to have multiple entries for a single field setting you need to create a repeater.
For example: lets say you have a Movie component and you need to list some credits. You can create a repeater and add a field setting with type string
and name it credit. In the movie editor you will able to add as many credit field you like.
Another example: imagine you setup a repeater with two children, a string and a asset field.
“age (structure) |__ default details (field_group) |__ slide (repeater) |__ title (string) |__ image (asset)
“
Then on the component editor you can
“y first page (component) |__ slide_1 |__ ‘My first slide’ |__ img_1.png |__ slide_2 |__ ‘My second slide’ |__ img_2.png |__ slide_3 |__ ‘My last slide’ |__ img_999.png
“
The code can be something like this:
“by @page = B.get_components(‘page’) .where(slug: ‘my-first-page’) .includes(repeaters: [:texts, :images]) .first
@page.get_repeater(‘slide’).each do |slide| slide.title slide.get_image_path end
“
To be able to use this helper in the application console you need to run Binda.include Bidna::DefaultHelpers
The repeater model Binda::Repeater
can make use of any of the field helpers.
Users
Binda offers two main roles. The super admin which is capable of administrating the entire website and the standard admin user which cannot manage the structures, field groups and field settings.
In case you cannot access with your account anymore you can create a new super admin via console running this task:
“sh rails binda:create_super_admin
“
Maintenance Mode
Binda offers a maintenance mode out-of-the-box. In your routes you will find:
“by
config/routes.rb
get ‘maintenance’, to: ‘maintenance#index’, as: ‘maintenance’
“
You can change the url to be whatever you like, as long as you keep the route name. For example
“by
config/routes.rb
get ‘under_construction’, to: ‘maintenance#index’, as: ‘maintenance’
“
The maintenance behaviour is controlled by the MaintenanceHelper
included in your app/controllers/application_controller.rb
. If you don’t have it make sure it’s included this way:
“by
app/controllers/application_controller.rb
include ::Binda::MaintenanceHelpers
“
Customize maintenance appeareance
The maintenance mode is controlled by the app/controllers/maintenance_controller.rb
which renders a single view: app/views/layouts/maintenance.html.erb
. You can do whatever you like with it.
To change appereance and behaviour of the page add your styles to app/assets/stylesheets/maintenance.scss
and your scripts to app/assets/javascript/maintenance.js
. These are manifest files so if you need jQuery for example, you just need to add //= jquery
at the top of maintenance.js
file.
Field settings and field groups
Orphans
Sometime playing with Rails console you might end up creating orphans, which basically are children of a parent that doesn’t exist anymore. They might cause errors in some queries and they are hard to track down.
To make sure you haven’t any orphan run the following commands from your shell:
“sh rails binda:remove_orphan_fields rails binda:remove_orphan_components rails binda:remote_orphan_boards
“
Missing Field instances
It might happen that a board or component doesn’t have a field even though a field setting exists. This might be caused by an improper use of the rails console. If you’re paranoid about it run the following command:
“sh rails binda:create_missing_field_instances
“
Plugins
Here a list of useful plugins:
Upgrade from a previous version
If you are going to upgrade from a previous version of Binda please check the guidelines attached to the version release which can be found on this Github page.
Create a Binda plugin
You can create a plugin to add new features to Binda. This is the most suitable and correct way to develop a new feature that will be possibly shared and use by everyone in the future.
The first step is to create a plugin.
“ails plugin new binda_new_feature –skip-test –dummy-path=spec/dummy –mountable
“his will create a folder binda_new_feature
which will contain your plugin BindaNewFeature
.
We will --skip-test
as we are going to use Rspec instead of standard Ruby on Rails test suite. For the same reason the --dummy-path
will change to spec/dummy
. Ultimately we want the plugin to be --mountable
.
Add dependencies
Populate binda_new_feature.gemspec
with dependencies and replace every TODO
with a content that makes sense.
“by
binda_new_feature.gemspec
$:.push File.expand_path(“../lib”, FILE)
Maintain your gem’s version:
require “binda_new_feature/version”
Describe your gem and declare its dependencies:
Gem::Specification.new do |s| s.name = “binda_new_feature” s.version = BindaNewFeature::VERSION s.authors = [Me] s.email = [me@mydomain.com] s.homepage = “http://mydomain.com” s.summary = “Binda New Feature is plugin for Binda CMS” s.description = “Use this plugin to enable new feature in your application” s.license = “MIT”
s.files = Dir[app,config,db,lib//, MIT-LICENSE, Rakefile, README.md]]
s.add_dependency “rails”, “>= 5.0”, “< 5.2” s.add_dependency “binda”, “~> 0.0”
# Test suite s.add_development_dependency “rspec-rails”, “>= 3.5”, “< 3.7” end
“
Make sure all dependencies are versioned in order to avoid issues due to deprecation in future releases. (The above versions are dated 07/2017)
Prepare plugin for testing
Before coding anything make sure you complete the following steps:
1) Install Rspec
“ails generate rspec:install
“
2) Install Binda on the dummy application
“d spec/dummy rails generate binda:install
“
3) Tell config.generators
to use Rspec:
“by
lib/binda_new_feature/engine.rb
module BindaNewFeature class Engine < ::Rails::Engine isolate_namespace BindaNewFeature
config.generators do |g|
g.test_framework :rspec
end
end end
“
This makes sure Rails uses Rspec to create test specs every time you generate something with rails g
command (be it a model, controller or scaffold).
4) change a line in spec/rails_helper.rb
“by
require File.expand_path(‘../../config/environment’, FILE)
should be changed to
require File.expand_path(‘../dummy/config/environment’, FILE)
“
Create a first test
Let’s create a fake controller to see if the plugin works.
“ails generate controller binda/foo index –skip-namespace
“
This command create a controller called Binda::Foo
which will be integrated to Binda
engine and, we have done everything correctly, we should have a spec ready to be populated with tests in spec/controllers/binda/foo_controller_spec.rb
.
Lets add Binda routes to that spec. (See why you need to specify routes here)
“by
spec/controllers/binda/foo_controller_spec.rb
require ‘rails_helper’
module BindaNewFeature RSpec.describe FooController, type: :controller do
# This line is very important
routes { Binda::Engine.routes }
describe 'GET #index' do
it 'returns http success' do
get :index
expect(response).to have_http_status(:success)
end
end
end end
“
The generator unfortunately creates a namespace inside BindaNewFeature::Engine.routes
which we will not use. Instead add the folloing lines which uses Binda::Engine.routes
“by
config/routes.rb
BindaNewFeature::Engine.routes.draw do end
Binda::Engine.routes.draw do get ‘foo’, to: ‘foo#index’ end
“
Now running rspec
the test should pass. (you might have 2 pending examples for foo helper and view, but that’s not a problem for now).
Extend a Binda models and controllers
Sometimes you want to add new methods to Binda models with your plugin. In order to do it you need to make your plugin aware of Binda and its models. To achive it require Binda at the top of the lib/binda_new_feature/engine.rb
like so:
“by require “binda”
“
If you want to access Binda::ApplicationController to inherit its methods change the parent_controller configuration of your plugin in the same file:
“by
lib/binda_new_feature/engine.rb
… all require
gems
module BindaNewFeature class Engine < ::Rails::Engine
# ... some other code
config.parent_controller = 'Binda::ApplicationController'
end end
“
How to create a form of nested components
Let’s say you have a component which depends on another components and you want your user to edit both of them in the same form. No problem.
“by
controller
Let’s say your structure has slug = my_structure
and id = 123
and you want to edit component_A
and its child component_B
@structure = Binda::Structure.find(123)
or if you use Friendly_id
@structure = Binda::Structure.friendly.find(‘my_structure’)
@component_A = @structure.components.detect{|c| c.slug == ‘component_A’} @component_B = @structure.components.detect{|c| c.slug == ‘component_B’}
“
“by
view
<%= simple_form_for @structure, html: { class: ‘some-form-class’ } do |f| %> <%= f.simple_fields_for :components, @component_A do |A| %> <=% A.input :name_of_a_column %> <=% A.input :name_of_another_column %> <% end %> <%= f.simple_fields_for :components, @component_B do |B| %> <=% B.input :name_of_a_column %> <=% B.input :name_of_another_column %> <% end %> <% end %>
“
How to contribute
Any contribution is more than welcome.
To contribute fork this project and clone the fork in your local machine. There you are free to experiment following this principles: - before diving into the code open a issue to explain what you’d like to do - don’t add gem dependencies unless it’s absolutely necessary - keep it simple and be DRY - add tests - comment your code following Yard guidelines principles (use yard server -r
to see the HTML version at http://localhost:8808
, if you make any change to the doc just refresh the page and the documentaion page gets updated automagically) - update the README.rb file, use Github markdown - if you are not adding a core feature consider writing a plugin instead - improve and/or add new I18n translations - when fixing a bug, provide a failing test case that your patch solves - write deprecation warning for methods instead of deleting them (app/models/concerns/binda/deprecations.rb
)
How to work locally
Ensure you have installed Binda dependencies.
“sh cd path/to/binda bundle install npm install
“
To see what you are actually doing you can make use of the dummy application which is shipped with Binda.
Ensure you have Postgres up and running, then create dummy databases.
“sh cd spec/dummy rails db:create
“
If you haven’t already, install Binda.
“sh rails generate binda:install
“
In order to edit javascript files you need to run Webpack and leave the terminal window open, so Webpack can compile everytime you save a file. To install Webpack run npm install
from the root of your application. Then everytime you want to edit a javascript file run:
“sh webpack
“
If you need to reset your database run the following commands
“d spec/dummy rails db:drop && rails db:create rails generate binda:setup
“
In order to make the dummy application flexible any update to that folder isn’t saved in the repository.
This let you as you prefer with your dummy without the hassle of cleaning it before creating a commit.
How to test
In order to avoid the it works on my machine issue, test are run via Travis every time a commit is pushed. Make sure you register your forked version on Travis in order to test every commit. If you don’t the forked version will be tested once you make a pull request to the original repository.
If you want (and you should) test locally Binda use RSpec, FactoryGirl and Capybara to run tests. You can find all specs in spec
folder. Capybara needs Firefox and Geckodriver to run so make sure you have it installed in your machine. If you have Node you can install Geckodriver via npm:
“sh npm install –global geckodriver
“
Some specs are run against the database. If you haven’t installed Binda on the dummy application yet run:
“sh RAILS_ENV=test rails db:migrate
“
The above command might generate an error. This is probably because you have previously installed Binda and the generator finds migration both in binda/db/migrate
and binda/spec/dummy/db/migrate
. To solve the issue, remove the spec/dummy/db/migrate
folder and run the previous command again.
“sh cd spec/dummy rm -rf db/migrate rails db:drop rails db:create RAILS_ENV=test rails db:migrate cd ../..
“
Here the oneliner:
“sh cd spec/dummy && rm -rf db/migrate && rails db:drop && rails db:create && RAILS_ENV=test rails db:migrate && cd ../..
“
If Binda migration have been updated then your schema.rb
is outdated and will generate false failing tests. In this case you need to run following command to refresh your database configuration:
“sh cd spec/dummy rm -r db/schema.rb rails db:drop rails db:create rails generate binda:install rm -rf db/migrate rm -rf config/initializers/devise_backup_.rb cd ../..
“
Here the oneliner:
“sh cd spec/dummy && rm -r db/schema.rb && rails db:drop && rails db:create && rails generate binda:install && rm -rf db/migrate && rm -rf config/initializers/devise_backup_.rb && cd ../..
“
If in the future you need to clean your dummy app code, simply run:
“sh rm -rf spec/dummy && git checkout spec/dummy
“
The command above should be run before any commit!
Once all setup is done run RSpec every time you update the specs:
“sh rpsec
“
Some helpful hints to debug tests are:
- Add
save_and_open_page
command in the code of the test example. This will save the page and let you inspect it. - Add
binding.pry
this will stop the test and let you inspect the code at that moment of the code. - In the command line, from Binda root folder, execute
tail -f ./spec/dummy/log/test.log
this will give you the list of operations executed by the server while you are running the test.
Update test coverage
Once tests are done update Code-Climate test coverage locally (Mac OSX).
“sh $ cd path/to/binda $ curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-0.1.4-darwin-amd64 > ./cc-test-reporter $ chmod +x ./cc-test-reporter $ ./cc-test-reporter before-build $ rspec $ ./cc-test-reporter after-build -r 7bffb1da50f35979ea3ef4fc205aa03c6b3c10fa603d5b66f19f81ab06d2ab97
“
cc-test-reporter
is ignored by the repo, so it want be pushed.
Same thing can be done on linux usign another binary code (see documentation). Besides the test coverage can be done automatically via Travis as well, but not on pull requests.
Binda versioning
It’s possible to test edge versions of Binda on real projects. Edge versions can be found only in the github repository and can be referenced by tag.
For example once v0.1.0
is published any new edge release which can be considered stable enough for a real project is tagged with alpha or beta (v0.1.1.alpha
, v0.1.1.alpha.1
, v0.1.1.beta
, etc). These tags won’t change and won’t be removed so you can safely add them to you gemfile like so:
“by gem ‘binda’, github: ‘lacolonia/binda’, ref: ‘v0.1.1.alpha.1’
“
The same tag is listed as the gem version, but it’s not published to Rubygems.
More info can be found at the semantic versioning documentation.
Bug reporting
Please refer to this guide. If you need direct help you can join Binda Slack Channel.
License
The gem is available as open source under the terms of the GNU General Public License v3.0.
Binda is a headless CMS with an intuitive out-of-the-box interface.
Copyright (C) 2017 Alessandro Barbieri
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
Find the GNU General Public License here http://www.gnu.org/licenses/.
Credits
Binda is inspired by Spina CMS.
We give also credit to authors and contributors of the gems that Binda uses. Huge thank you to all of them.
Who is Binda?
Is this guy here.