A developer's journey through BrowserCms.

Tuesday, June 4, 2013

Adding a custom route engine

When customizing BrowserCms, I have found it useful to separate core BrowserCms code from my own. Namespacing is a great way to accomplish that. I like grouping my custom content blocks in related sections and not simply adding yet another content block to the 'cms' namespace.



Note: the last diagram in the attachment is from the browsercms code (I forked the github repo to include this change). The other diagrams are from a BrowserCms app instance.

See the detailed diagrams for more information.

The 'block_path' route view helper

‘block_path’ is an interesting beast.  It looks like a typical view helper (i.e., _path, _url), but it introspects the content block object and creates an array of objects and values that will be used by ‘link_to’ to generate a path.  (For more details on this style of route specification, see Creating Paths and URLs From Objects, section '2.8 Creating Paths and URLs From Objects')



The engine can be the default cms engine that comes with BrowserCms, the vanilla Rails engine, or another custom engine.

The action parameter is filled with special bcms actions, like ‘:versions’.

Then using the block, objects are extracted and included in the path; these objects will be translated into keys values for tables (this is nothing new).

Resolving undefined method 'cms_number_field'

After creating a custom content block for BrowserCms, if you had specified any 'integer' type in your generate command, you might see something like this when you go to create an instance of that content:

NAMESPACE=bcms_my401k ./bin/rails g cms:content_block BcmsMy401k::Widget user_id:integer name:string description:text
For some reason, when generating content blocks, integers are mapped to ‘cms_number_field’ form helpers, but they don’t seem to exist.

To resolve this issue, we simply need to provide the missing components that BrowserCms is complaining about.
  1. include 'number_field' in the list of form helper methods generated at load time
  2. associate a partial with the new form helper


Although this solution (creating a partial) is currently identical to ‘cms_text_field’, the partial could be updated later to validate a numeric entry.

Down migration issues with custom content blocks

While running down migrations that were created as a result from generating a custom content block type, 'def change' doesn't seem to be creating a 'down' migration. Perhaps it doesn't know what to do with the call to 'create_content_table'. I am hopeful that is the problem and not something with the latest ActiveRecord code.

In any case, when a migration is complex enough that it does not know how to create a 'down' migration from the 'up' syntax in the 'def change' method block, it is required to revert back to the old style, specifying 'def self.up' and 'def self.down' method blocks:

Thursday, May 30, 2013

Resolving issue with custom content blocks and version listings

BrowserCms provides generators that can be used to create custom content blocks.  This means that you can create models that inherit all the other niceties that come packaged with BrowserCms, like version control, including in pages, etc.

One hiccup I discovered was that the wrong routes were being used for any custom content blocks, even those that come from the sanctioned bcms_blog plugin.

To duplicate the issue,
  1. navigate to the cms content library: http://localhost/cms/content_library
  2. select one of the custom content block category types (e.g., Blog, if you have the bcms_blog plugin installed)
  3. create new content and edit and publish it several times
  4. list the entries (e.g., Blog > Blog Post)
  5. click on the entry that you edited
  6. click on 'List Versions'
  7. click on one of the versions
  8. click on 'View Content'
You are rewarded with a HTTP 404 warning:


Why is the page not found?  Take a look at the route.  It suggests that the resource be found under the 'cms' namespace.  That seems to be the problem; the bcms_blog uses its own namespace (bcms_blog) to avoid route conflicts.  So what's responsible for putting 'cms' in the view links.  The correct namespaces are used up until 'List Versions' is clicked and the page is refreshed.

I tracked down the issue with the JavaScript to the app/views/cms/blocks/versions.html.erb view.  The existing code was assuming that all custom content blocks use the 'cms' namespace.  This may not be the case, as with the bcms_blog plugin that has it's own Rails::Engine and, consequently, it's own route namespace.

By introducing some logic in the view's JavaScript, we can dynamically determine what namespace should be applied:

And the code to determine 'cmd_namespace'...

There are certainly more elegant solutions, but here is my short term solution with an idea of how to solve it better.

Wednesday, May 8, 2013

Create a new content_block type

I have really enjoyed using BrowserCms for my content management Rails applications. Besides coming packaged with a lot of great features from the get-go, it is quite accommodating for personalizing the user's experience while still tapping into BrowserCms's great features. For example, content_block models have features such as security, version control, and WYSISYG form elements. When it is required to add models to your app, to gain access to those features, one easy method is to use the BrowserCms's content_block generator. Of course, BrowserCms does have documentation for this process, but I wanted to have greater control over the namespace for the generated elements. I had to make some changes to the BrowserCms generator, and was successful.

Create a new content_block type for a BrowserCms application in a specified namespace.

Note: the original browsercms generator for content_block was altered ever so slightly. This example depends on the changes made in my forked copy of browsercms.

Friday, April 5, 2013

CKEditor instances and Ajax

I spent a little time trying to figure out how to manage the CKEditors on an authoring page. For the bulk of my solution, I give credit to StackOverflow. As noted in the example below, I did need to comment out the line with CKEDITOR.replace(instance); to get things working on my end.

If I understand this issue correctly, because I am using Ajax, the instances remain in memory. As I navigate to each page in my wizard, Ajax is used to get a fresh copy of the page partial. Each time the editor page is requested, the id values for the CKEditor instances is slightly different. CKEDITOR.instances lists registered editors that have been loaded. Those instances need to be cleared out in order to successfully load the new CKEditor instances.

I created a new helper method to generate CKEditor without the option to switch to plain text. Here is the template:

Here is the form helper:

Thursday, April 4, 2013

It would help to check Capybara output!

I was battling with my cucumber tests recently. The problem was that the wrong user was being setup for the tests. I was seeing 'unauthorized access' in Firefox (WebDriver). Also, WebDriver's activity is logged in 'logs/test' and that was reporting unauthorized access as well.

Sure enough, I was mistaking 'registered user' for an authorized user. A registered user does not have special editing and publishing permissions (at least for vanilla BrowserCms).

When I correctly assigned the user login, I got a little further.

Ok; almost there. The remaining issue was that my cmsuser account is getting truncated after the first test. That explains why the first scenario works and the others don't.

Finally, tests are passing again.

./bin/cucumber -r features --drb features/pages.feature

Project cucumber features

Wednesday, April 3, 2013

testing's delicate balance

When adding scenarios, especially those with the @javascript tag, you may need to be aware of tables that should not be truncated, unless after truncating the tables they are seeded for the next run. This latter solution is not one we are currently using. Instead, we include the tables that are not changing, that are being used in multiple tests, in the list of exception tables that will not be truncated at the end of each scenario.

In addition to adding exception tables, you will need to include more seed data for the tables that are not being changed and are used across several scenarios.

I created some custom content blocks for article and layout records. Unless a separate Rails::Engine is used to generate routes, it appears that content blocks must reside under the Cms:: namespace. By creating BcmsMy401k::Engine, I was able to establish the BcmsMy401k:: namespace. This also meant that I needed to add routes via BcmsMy401k::Engine instead of Rails::Application.

For some reason, however, the routes are being loaded twice. I will need to figure out why, but for now, I check to see if the routes were loaded already for the BcmsMy401k::Engine. I do this by analyzing the routes already drawn. I chose to check by using the ActionDispatch::Routing::RouteSet::NamedRouteCollection#names method. If the count is greater than 0, then they've already been loaded. The routes should only be loaded one time. This solution will allow me to move forward; I'll have to investigate a better solution later.

Related resources:

Monday, April 1, 2013

app/models/cms.rb
This little file is responsible for appending "cms_" to all the table names for Cms models so that the actual table names in the database are not actually prefixed.  The only exception seems to be Cms::Attachment.
module Cms
  def self.table_name_prefix
    #'cms_'
    ''
  end
end
In order for my tests to run in my application that uses browsercms, I needed to configure an empty string to be returned.  The development environment had already weeded out 'cms_' somewhere else in the code.  The test environment needs to have this value set to empty string.

Friday, March 29, 2013

Multi-Site Functionality for BrowserCms

I want to add multi-site functionality to BrowserCms, but first wanted to verify that all the tests pass.  I battled a little bit with getting the tests to pass because of how I use Gemfile binstubs (bundle install --binstubs) and how I like developing with an unpacked gem.  My findings have been posted to Google Groups:

Aruba doesn't seem to be writing files; cucumber tests failing

Running factories through rails console

This might be a good way to start understanding how objects are created in BrowserCms and how they connect with each other.

I extracted out the values from the cucumber configuration file (features/support/env.rb) and then I paste them into ./bin/rails c.  Keep  test/factories/factories.rb handy to generate database records using the supplied factories.
./bin/rails console
require File.expand_path('./test/support/factory_helpers')
require File.expand_path('./test/support/database_helpers')
require File.expand_path('./test/factories/factories')
require File.expand_path('./test/factories/attachable_factories')
require File.expand_path('./test/mock_file.rb')

include FactoryGirl::Syntax::Methods
include FactoryHelpers