Twice Baked Core
TB Core is the base Twice Baked engine that provides user authentication, roles, and an admin dashboard upon which CRUD apps can be built. Use TB Core to power content-managed websites or as a quick-and-simple way to add a backend to your existing data models.
Requirements
TB Core 1.2.x and higher requires Rails 4 and is developed using Ruby 2.1. Lower versions of Ruby may continue to work but are not heavily tested.
For Rails 3 compatiblity, stick to TB Core 1.1.x.
Installation/Usage
In your Gemfile add the following
gem 'tb_core'
Run bundle install
Run the setup generator to copy in the base templates and migrations
rails g spud:setup
run a rails server instance and point your browser to /admin
Setup Tasks
The spud:setup
generator takes care of a few tasks for you. If you missed that step or would like to complete them manually, they are listed below:
- Your base
ApplicationController
should extend fromSpud::ApplicationController
. - Your base
application.html.erb
should include a few special head tags (see generator template for example). - You should copy in the base migrations with
rake railties:install:migrations
.
Configuration
The core engine provides various configuration options.
Spud::Core.configure do |config|
config.option = value
...
end
admin_applications
: Array of custom admin modules. See section below for more info.site_name
: Controls the site name displayed in the dashboard andtb_page_title
view helper.from_address
: Sender address used for password resets and other mailers.production_alert_domain
: When set, displays a prominent warning bar in the admin dashboard directing users to the production domain. You should only set this value inconfig/environments/staging.rb
.
Adding Apps to the Dashboard
The fastest way to add an app to the dashboard is via the geneator. The generator will take care of creating a model as well as a set of controllers/views.
rails g spud:module Cars make:string model:string year:integer classic:boolean notes:text
Admin apps are added via the Spud::Core.config.admin_applications
array. We recommend you perform this action in either an initializer or within your application.rb
file.
Spud::Core.config.admin_applications += [{
# Required:
:name => "Clients",
:thumbnail => "spud/admin/clients.png",
:url => "/admin/clients",
# Optional:
:badge => ->(user){ Client.where(:is_pending => true).count() }
}]
Build out your RESTful controller and views like you normally would in any Rails app. Extend your controller from Admin::ApplicationController
in order to inherit the default admin behaviors, and look at the core admin controllers for example implementations.
Roles & Permissions
A user can be assigned to a role, which itself has one or more permissions. These permissions serve two distinct purposes: Determining what dashboard apps a user has access to (if any), and being used within your application logic to establish fine-grained user abilities.
Checking permissions is easy. Each permission has a tag
which is a unique, namespaced identifier. Use the has_permission?
and has_any_permission?
methods on the user object to check for their existence. Keep in mind that these calls will always return true for users who have the super_admin
flag set.
if !@spud_user.('my_website.clients.my_clients')
redirect_to root_path, :notice => 'Permission Denied!'
end
Permissions are created one of two ways:
- Every dashboard app automatically generates a "Full Access" permission, with a tag of
admin.(app name).full_access
. - You as the developer may append custom permissions to the
Spud::Core.permissions
array.
Create custom permissions whenever you need to permit an action that falls outside of the standard "full access to an app" use case; For example, turning on/off the ability for a user to upload an avatar.
// application.rb
Spud::Core.permissions += [
{:tag => 'my_website.profile.avatar', :name => 'Upload an avatar to my profile'}
]
// some_view.html.erb
<% if current_user.has_permission?('my_website.profile.avatar') %>
<%= link_to 'Upload Avatar', upload_avatar_path %>
<% end %>
Finally, custom permissions may optionally be tied to one or more dashboard apps. A user who has the permission shown below would have access to the the Clients and Projects dashboard apps. After that is is up to you to code your view and controller logic in accorance to what permissions the user has.
// application.rb
Spud::Core.permissions += [{
:tag => 'my_website.projects.project_management',
:name => 'Manage clients and projects, but cannot delete them or view private info',
:apps => [:clients, :projects]
}]
Extending the User Model
A common requirement is to add custom fields and functionality to the base spud_user
model. We have provided several spots where you can do this.
Adding custom methods and attributes to the SpudUser class
Create a file in your app at app/models/spud_user.rb
, and build a class called SpudUser
that extends from Spud::SpudUserModel
. You do not need any explicit requires - the autoloader will take care of the rest.
class SpudUser < Spud::SpudUserModel
has_attached_file :avatar
attr_accessible :avatar
def say_hello
return "Hello, World!"
end
end
Adding fields to the add/edit user form
Create a file in your app at app/views/admin/users/_form_additions.html.erb
.
<div class="control-group">
<%= f.label :avatar, :class=>"control-label"%>
<div class="controls">
<%= f.file_field :avatar %>
</div>
</div>
Adding fields to the user show action
Create a file in your app at app/views/admin/users/_show_additions.html.erb
.
<% if @user.avatar_file_name %>
<dt>Avatar</dt>
<dd>
<%= image_tag @user.avatar.url(:thumb) %>
</dd>
<% end %>
404 Handling
The base Spud::ApplicationController
will automatically rescue from any Spud::NotFoundError
and Spud::AccessDeniedError
errors by rendering out the layouts/error_page.html
template. To customize this view, create a template by that name in your own project.
When building your own apps you may raise a Spud::NotFoundError
at any time to halt further execution and cause the 404 page to render. For example:
class CarsController
before_action :get_record
# ... actions here
def get_record
@car = Car.where(:id => params[:id]).first
if @car.blank?
raise Spud::NotFoundError.new(:item => 'car')
end
end
end
Testing
Twice Baked uses RSpec, Capybara and Jasmine for testing. Get the tests running with a few short commands:
Create and migrate the databases:
rake db:create rake db:migrate
Load the schema in to the test database:
rake app:db:test:prepare
Run the tests with RSpec
rspec spec
After the tests have completed the current code coverage stats is available by opening /coverage/index.html
in a browser.
Jasmine
For running the javascript unit tets:
rake jasmine:ci