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
gem install binda
alternatively add the gem to your application's Gemfile:
gem 'binda'
Then execute:
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.
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.
rails generate binda:setup
Credentials
If you have lost your username/password you can run
rails 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
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:
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:
@my_structure = Binda::Structure.find_by(slug: 'my-structure')
From that you can do all sorts of things.
# 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: {structure_id: @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:
# 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:
@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.
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
@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.
@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:
# SLOW
@structure = Binda::Structure.find_by( slug: 'my-structure')
@components = @structure.components
Do this instead!
# 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:
@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
:
# 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:
@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.
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:
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:
# 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:
# 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.
Helper | ||
---|---|---|
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
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:
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.
page (structure)
|__ default details (field_group)
|__ slide (repeater)
|__ title (string)
|__ image (asset)
Then on the component editor you can
My 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:
@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:
rails binda:create_super_admin
Maintenance Mode
Binda offers a maintenance mode out-of-the-box. In your routes you will find:
# 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
# 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:
# 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:
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:
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.
rails plugin new binda_new_feature --skip-test --dummy-path=spec/dummy --mountable
This 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.
# 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:
- Install Rspec
rails generate rspec:install
- Install Binda on the dummy application
cd spec/dummy
rails generate binda:install
- Tell
config.generators
to use Rspec:
# 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).
- change a line in
spec/rails_helper.rb
#Â 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.
rails 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)
# 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
# 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:
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:
# 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.
# 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'}
# 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 athttp://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.
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.
cd spec/dummy
rails db:create
If you haven't already, install Binda.
rails generate binda:install
This should automatically launch binda:setup, which prompts you to enter an email address and a password. If this doesn't enter you have to launch it manually
rails generate binda:setup
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:
webpack
If you need to reset your database run the following commands
cd 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:
npm install --global geckodriver
Some specs are run against the database. If you haven't installed Binda on the dummy application yet run:
RAILS_ENV=test rails db:migrate
Sometimes this isn't possible because you have already a database present and other times you might get ActiveRecord::PendingMigrationError: Migrations are pending. To resolve this issue, run: bin/rails db:migrate RAILS_ENV=test
Therefore, instead of db:migrate
use the following command:
RAILS_ENV=test rails db:reset
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.
cd spec/dummy
rm -rf db/migrate
rails db:drop
rails db:create
rails db:test:prepare
cd ../..
Here the oneliner:
cd spec/dummy && rm -rf db/migrate && rails db:drop && rails db:create && rails db:test:prepare && 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:
cd spec/dummy
rm -r db/schema.rb
rails db:drop
rails db:create
rails generate binda:install
rails db:test:prepare
rm -rf db/migrate
rm -rf config/initializers/devise_backup_*.rb
cd ../..
Here the oneliner:
cd spec/dummy && rm -r db/schema.rb && rails db:drop && rails db:create && rails generate binda:install && rails db:test:prepare && 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:
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:
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).
$ 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:
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/.
Open Source Tools
Binda is supported by those amazing services which are giving invaluable help in making Binda a better tool:
Jet Brains is the main tool for developing Binda code. | |
Browserstack is the best way to make sure Binda interface is consistent on every browser and device. | |
Code Climate is an amazing tool to ensure code quality are at the highest standard. | |
Travis CI takes care of testing every pull request which is an invaluable help. |
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.