Nov 11 2007

Naming Conventions - Ruby and Ruby on Rails

etienne @ 10:02 pm

In  an attempt to see if I can get my "Ruby and Rails Naming Conventions" article back on Google I’ve created this entry to see if it gets listed.

Click on the link to access the actual article Ruby and Rails Naming Conventions

Sorry for the inconvenience.

 


Nov 09 2007

Ruby and Rails Naming Conventions Article Missing from Search Engines

admin @ 7:44 am

Over the past week or two I’ve noticed traffic to my Blog have dropped dramatically. Upon further investigation I have found that traffic to one of the most popular articles "Ruby and Rails Naming Conventions" have almost dropped to zero.

I’ve checked Google and the other search engines and this article does not appear at all when using the following search terms "rails naming conventions", it use to be one of the top five for quite some time.

I have searched the Internet to try and figure out why my article is no longer listed, but as yet I’ve not found anything that may explain why this has happened. If anyone has any ideas it would be much appreciated if you could let me know. I’m not sure if I can approach Google about this as this seems to be the same for all search engines.

Click on this link to access the actual article Ruby and Rails Naming Conventions 


Oct 28 2007

Ruby and Rails Naming Conventions

etienne @ 10:15 am

I’ve been looking for a consolidated list of all Ruby and Rails naming conventions without too much luck so I’ve started my own. I find I always forget the naming convention especially as I move between projects that use different languages.

Please let me know of any others that I have missed. 

Naming Conventions

Ruby Naming Convention

Ruby uses the first character of the name to help it determine it’s intended use.

Local Variables
Lowercase letter followed by other characters, naming convention states that it is better to use underscores rather than camelBack for multiple word names, e.g. mileage, variable_xyz

Instance Variables
Instance variables are defined using the single "at" sign (@) followed by a name. It is suggested that a lowercase letter should be used after the @, e.g. @colour 

Instance Methods
Method names should start with a lowercase letter, and may be followed by digits, underscores, and letters, e.g. paint, close_the_door

Class Variables
Class variable names start with a double "at" sign (@@) and may be followed by digits, underscores, and letters, e.g. @@colour

Constant
Constant names start with an uppercase letter followed by other characters. Constant objects are by convention named using all uppercase letters and underscores between words, e.g. THIS_IS_A_CONSTANT

Class and Module
Class and module names starts with an uppercase letter, by convention they are named using MixedCase, e.g. module Encryption, class MixedCase

Global Variables
Starts with a dollar ($) sign followed by other characters, e.g. $global

Rails Naming Convention

Rails use the same naming convention as Ruby with some additions:

Variable
Variables are named where all letters are lowercase and words are separated by underscores, e.g. order_amount, total

Class and Module
Classes and modules use MixedCase and have no underscores, each word starts with a uppercase letter, e.g. InvoiceItem

Database Table
Table names have all lowercase letters and underscores between words, also all table names need to be plural, e.g. invoice_items, orders

Model 
The model is named using the class naming convention of unbroken MixedCase and is always the singular of the table name, e.g. table name might be orders, the model name would be Order. Rails will then look for the class definition in a file called order.rb in the /app/models directory. If the model class name has multiple capitalised words, the table name is assumed to have underscores between these words.

Controller
Controller class names are pluralized, such that OrdersController would be the controller class for the orders table.  Rails will then look for the class definition in a file called orders_controller.rb in the /app/controllers directory.

Files, Directories and other pluralization
Files are named using lowercase and underscores. Assuming we have an Orders controller then the following other conventions will apply:

  • That there is a helper module named OrdersHelper in the orders_helper.rb found in the app/helpers directory
  • Rails will look for view template files for the controller in the app/views/orders directory
  • Output from this view will then be used in the layout defined in the orders.html.erb in the app/views/layouts directory
  • Test files including order_test.rb will be created in the /test/unit directory, a file will be created in the /test/fixtures directory called orders.yml and finally a file called orders_controller_test.rb will be created in the /test/functional directory

Primary Key
The primary key of a table is assumed to be named id.

Foreign Key
The foreign key is named with the singular version of the target table name with _id appended to it, e.g. order_id in the items table where we have items linked to the orders table.

Many to Many Link Tables
Tables used to join two tables in a many to many relationship is named using the table names they link, with the table names in alphabetical order, for example items_orders.

Automated Record Timestamps
You can get ActiveRecord to automatically update the create and update times of records in a database table. To do this create two specially named columns created_at and updated_at to your table, i.e. t.datetime :created_at and t.datetime :updated_at. If you only want to store the date rather than a date and time, use :created_on and :updated_on.

Naming Convention Summary 

Model Naming Convention

Table: orders
Class: Order
File: /app/models/order.rb
Primary Key: id
Foreign Key: customer_id
Link Tables: items_orders

Controller Naming Convention

Class: OrdersController
File: /app/controllers/orders_controller.rb
Layout: /app/layouts/orders.html.erb

View Naming Convention

Helper: /app/helpers/orders_helper.rb
Helper Module: OrdersHelper
Views: /app/views/orders/… (list.html.erb for example)

Tests Naming Convention

Unit: /test/unit/order_test.rb
Functional: /test/functional/orders_controller_test.rb
Fixtures: /test/fixtures/orders.yml

  


Oct 21 2007

Ruby on Rails Survey Builder

etienne @ 7:17 pm

 

Update 9 January 2008: SMERF Released!

Update 2 January 2008: Announcing SMERF - Simple MEta Rails Form plugin

Over the past few weeks I have been developing a general purpose survey/questionnaire builder that makes it easy to create a new survey, present it to the user, record the user’s responses in a database, and allow the user to recall and update the responses. It’s still in it’s infancy and I will add more functionality as required, for now it’s functional enough to meet all the requirements of the current project.

To create a new survey we define the content of the survey using a YAML file. I decided to use YAML as it seems to be the defacto standard for Rails, it’s simple and has a nice hierarchical structure which suits the way surveys are structured.

Survey Structure

Each survey is made up of any number of question groups, within each group there are any number of questions. Questions can accept free form text or present a list of options to the user. In some cases a particular answer may require additional information, this can be done using subquestions. Subquestions can be nested to any depth, i.e. a subquestion can present a set of answers, which in turn can present another subquestion with another set of answers and so on. The diagram below shows the structure of a survey:

  Survey Structure

 

Defining the Survey

When setting up a new survey the first thing we do is define some settings for the survey as a whole. Currently the following items can be defined for the survey:

  • name: Name of the survey (mandatory)
  • welcome: Message displayed at the start of the survey (optional)
  • thank_you: Message displayed at the end of the survey (optional)
  • group_sort_order_field: Nominates which group field to use when sorting groups for display (mandatory)
  • groups: Defines the question groups within the survey (mandatory)

Here is the definition for our demo survey:


survey:
  name: Demo

  welcome: |
    <b>Welcome:</b><br>
    Thank you for taking part in our demo survey we appreciate your
    input.<br><br>

    <b>PRIVACY STATEMENT</b><br>
    We will keep all the information you provide private and not share
    it with anyone else….<br>

  thank_you: |
    <b>Thank you for your input.</b><br><br>

    Should you wish to discuss this survey please contact<br>
    Joe Bloggs<br>
    Tel. 12 345 678<br>
    e-mail <A HREF=\"
mailto:jbloggs@xyz.com.au\">Joe’s email</A><br><br>
 
    February 2007

  group_sort_order_field: code-

  groups:
  …

 As you can see from the example you are able to embed any HTML code within the text.

Defining Groups

Each survey is divided up into groups of questions, you must have at least one group per survey. Here are the fields that are currently available when defining a group:

  • code: This code must be unique for all groups within the survey as it is used to identify each group (mandatory)
  • name: The name of the group, this is displayed as the group heading (mandatory)
  • description: Give a more detailed description/instructions for the group (optional)
  • questions: Defines all the questions contained within this group (mandatory)

Here is the definition for the Personal Details group of the Demo survey:

  groups:
    personal_details:
      code: 1
      name: Personal Details
      description: | A brief description of this group…
      questions:
      …

Group example

 

Defining Questions 

A group can contain any number of questions, there must be at least one question per group. When defining a question you must specify the question type, the type determines the type of form field that will be created. There are currently four types that can be used, this will be expanded as needed. The current question types are:

  • multiplechoice: Allows the user to select all of the answers that apply from a list of possible choices, check boxes are used for this question type as multiple selections can be made
  • singlechoice: Allows the user to select one answer from a list of possible choices, radio buttons are used for the question type as only a single answer can be selected
  • textbox: Allows the user to enter a large amount of free text, the size of the text box can be specified
  • textfield: Allows the user to enter a small amount of free form text, the size of the text field can be specified

Question types

The following fields can be used to define a question:

  • code: Unique code that will identify the question, the code must be unique within a survey (mandatory)
  • type: Specifies the type of field that should be constructed on the form for this question, see above list for current types (mandatory)
  • question: The text of the question, this field is optional as subquestions do not have to have question text
  • textbox_size: Specifies the size of the text box to construct, rows x cols, defaults to 30×5 (optional)
  • textfield_size: Specified the size of the text field that should be constructed, specified in the number of visible characters, default to 30 (optional)
  • header: Specifies a separate heading for the question. The text will be displayed above the question allowing questions to be broken up into subsections (optional)
  • required: Specifies that an answer is required for this question
  • sort_order: Specifies the sort order for the question
  • help: Help text that will be displayed below the question
  • answers: Defines the answers to the question if the question type displays a list of possibilities to the user

 Below is an example question definition:

      questions:
        which_industry:
          code: g2q1
          type: multiplechoice
          sort_order: 1
          question: | Which industries have you worked in 
          help: | Mark <b>all</b> that apply                
          answers:
          …

Question example

 

Defining Answers

If the question presents a list of possible answers to the user then we can easily define these answers by using the following fields:

  • code: Code to uniquely identify the answer, code needs to be unique for each question (mandatory)
  • answer: The text that will be displayed to the user (mandatory)
  • default: If set to Y then this answer will be selected by default (optional)
  • sort_order: The sort order for this answer (mandatory)
  • subquestions: Some answers may need additional information, another question can be defined to obtain this information. To define a subquestions the same fields that define a normal question is used (optional)

Here is an example answer definition:

           answers:
            it:
              code: 1
              answer: | Information Technology
              sort_order: 1
              default: N
              subquestions:
              …

Defining Subquestions 

Additional questions can be defined for an answer if more information is required if the user selects the answer. For example you may have an answer ‘Other’ that required additional information from the user. A subquestion can be defined for the ‘Other’ answer that takes an additional input from the user. To define a subquestion you use the same fields as for a normal question (Refer to the Defining Question section above).

Below is an example subquestion definition:

              subquestions:
                other_industries:
                    code: g2q1a4s1
                    type: textbox
                    sort_order: 1
                    question:
                    help: | Please specify
                    textbox_size: 30×3
 

Subquestion example

 

 

Data Store

There are three tables used by the survey builder, a surveys table that stores the survey details, a surveys_users table that stores a users answers for a survey and finally the users table.

When a user selects to view a survey the system checks the survey definition file to see if any changes have been made since the last time the survey was loaded, if it has the survey definition file is processed and validated. A set of classes and objects are created that describes the survey including SurveyFile, SurveyGroup, SurveyQuestion, SurveyAnswer, these are serialized to YAML format and stored in a single database field within the surveys table. If no changes have been made to the definition file then the survey is simply read from the surveys table and serialized from YAML with all classes and objects reconstructed.

User survey answers are stored  in the surveys_users table in a single field within the table. The answers are serialized to YAML and stored in the database field, the classes and objects are reconstructed when the record is retrieved.

Validation and Errors

The only validation currently performed  is to check that mandatory questions have been answered. In the near future I will be expanding validations by adding the ability to use regular expressions to validate the format of answers. I’m also thinking about allowing Ruby code to be specified to construct validation code that can be executed to check answers.

When an error is detected, a summary of the errors are displayed at the top of the form, additionally an error message is displayed for each question that has an error. This makes it very easy for the user to see which question they need to fix.

Error example

 

 Complete Example

Here is the complete survey definition fie for the Demo survey:


survey:
  name: Demo
  welcome: |
    <b>Welcome:</b><br>
    Thank you for taking part in our demo survey we appreciate your
    input.<br><br>

    <b>PRIVACY STATEMENT</b><br>
    We will keep all the information you provide private and not share
    it with anyone else….<br>

  thank_you: |
    <b>Thank you for your input.</b><br><br>

    Should you wish to discuss this survey please contact<br>
    Joe Bloggs<br>
    Tel. 12 345 678<br>
    e-mail <A HREF=\"
mailto:jbloggs@xyz.com.au\">Joe’s email</A><br><br>
 
    February 2007
  group_sort_order_field: code

  groups:
   
personal_details:
      code: 1
      name: Personal Details
      description: | A brief description of this group…
      questions:
       
specify_your_age:
          code: g1q1
          type: singlechoice
          sort_order: 1
          question: | Specify your age 
          help: | Select the <b>one</b> that apply
          required: Y
          answers:
            1_20:
              code: 1
              answer: | 1-20
              sort_order: 1
              default: N
           
21_40:
              code: 2
              answer: | 21_40
              sort_order: 2
              default: N
            >40:
              code: 3
              answer: | > 40
              sort_order: 3
              default: N
              subquestions:
               
>40:
                  code: g1q1a3s1
                  type: singlechoice
                  sort_order: 1
                  question: | Are you aged over 40
                  help: | Select the <b>one</b> that apply
                  answers:
                    41_50:
                      code: 1
                      answer: | 41-50
                      sort_order: 1
                      default: N
                    51_60:
                      code: 2
                      answer: | 51_60
                      sort_order: 2
                      default: N
                    >61:
                      code: 3
                      answer: | > 61
                      sort_order: 3
                      default: N

        are_you_married:
          code: g1q2
          type: singlechoice
          sort_order: 2
          question: | Are you married 
          help:
          required: N
          answers:
            no:
              code: 1
              answer: | No
              sort_order: 1
              default: Y
            yes:
              code: 2
              answer: | Yes
              sort_order: 2
              default: N

    employment_details:
      code: 2
      name: | EMPLOYMENT DETAILS
      description: | Brief description of the employment details group 
      question_sort_order_field: sort_order
      questions:
        which_industry:
          code: g2q1
          type: multiplechoice
          sort_order: 1
          question: | Which industries have you worked in 
          help: | Mark <b>all</b> that apply               
          answers:
            it:
              code: 1
              answer: | Information Technology
              sort_order: 1
              default: N
            accounting:
              code: 2
              answer: | Accounting
              sort_order: 2
              default: N
            finance:
              code: 3
              answer: | Finance
              sort_order: 3
              default: N
            other:
              code: 4
              answer: | Other
              sort_order: 4
              default: N
              subquestions:
                other_industries:
                    code: g2q1a4s1
                    type: textbox
                    sort_order: 1
                    question:
                    help: | Please specify
                    textbox_size: 30×3

        how_many_years:
          code: g2q3
          type: textfield
          sort_order: 3
          header:
          question: | How many years have you worked in the industry
          textfield_size: 10
          help:

Complete example 

 


Sep 02 2007

Views and nil Database Objects

etienne @ 6:04 pm

When a database field in a table is NULL and this field is then used in a view a nil object exception will be raised. So for example if I had the following code to display the name of the user in my view and the login field was NULL an error would be generated as login object would be nil. 

Signed in as <%= current_user.login %>

To overcome this you would need to use something like the code below:

Signed in as <%= current_user.login unless current_user.login.blank? %>

Which if you have many field to deal with becomes a major pain. As I was reading about this I realised that nil in Ruby is an actual object that has methods including to_s which will return an empty string when called. So instead I can do the following:

Signed in as <%= current_user.login.to_s %>

When the login field is NULL a nil object will be returned and the to_s message sent to this object which in turn will return an empty string, no error messages will be generted and everything works nicely.


Aug 26 2007

Ruby on Rails Class Serialize Problem

etienne @ 6:23 pm

I’ve been chasing my tail for the past day trying to track down a problem I was having in serializing a hash that contained two of my custom classes. I have two custom classes:

class Menu

end

class Permissions

end

I then have an ActiveRecord class that stores instances of these two classes in a hash which is then saved to my database.

class Role < ActiveRecord::Base

  serialize :credentials
  …
  self.credentials[:permissions] = Permissions.new(self)
  self.credentials[:menu] = Menu.new(self)
  …
end

After saving the record to the database I could inspect the field and all the YAML code was present and accounted for, the problem was that when I went to retrieve the serialized field, instead of getting back a hash with my two custom classes (i.e. Menu and Permissions) I was getting both objects of class YAML::Object.

After pulling my hair out for some time, I traced into the Rails code and saw that YAML::Load(string) was being called to unserialize the data. I then went to the YAML site and read more about the library which I admit I have limited knowledge about. I figured out that for some reason YAML was not finding my custom class definitions which meant it used YAML::Object. So now it was a matter of finding out how to tell YAML about my classes.

After doing more searching on the net I came across these articles which gave me the information I needed:

http://yaml4r.sourceforge.net/doc/page/type_families.htm
http://dev.rubyonrails.org/ticket/7537

I was able to add the following code to my environment.rb which will ensure any ActiveRecord derived classes will be correctly serialized. I also added two require statements to environment.rb to make sure my custom (non ActiveRecord derived) classes where also correctly serialized.

require ‘permissions’
require ‘menu’

YAML.add_domain_type("ActiveRecord,2007", "") do |type, val|
  klass = type.split(’:').last.constantize
  YAML.object_maker(klass, val)
end

class ActiveRecord::Base
  def to_yaml_type
    "!ActiveRecord,2007/#{self.class}"
  end
end

class ActiveRecord::Base
  def to_yaml_properties
    [’@attributes’]
  end
end

I restarted my server and everything worked !!!

 


Aug 19 2007

fieldWithErrors Overrides my CSS Field Classes

etienne @ 6:07 pm

When there are errors on a form, Rails will normally create a <DIV> element with the fieldWithErrors class wrapped around the fields input statement. If you have your own CSS class wrapped around a field this will be overridden by the fieldWithErrors <DIV> which is a pain.

I was searching for a solution when I found this post:

I’d like to say I came up with this, but I actually found it somewhere else.

I have the following inside my environment.rb file:

ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
  msg = instance.error_message
  error_style = "background-color: #f2afaf"
  if html_tag =~ /<(input|textarea|select)[^>]+style=/
    style_attribute = html_tag =~ /style=[’"]/
    html_tag.insert(style_attribute + 7, "#{error_style}; ")
  elsif html_tag =~ /<(input|textarea|select)/
    first_whitespace = html_tag =~ /\s/
    html_tag[first_whitespace] = " style=’#{error_style}’ "
  end
  html_tag
end

I now get the desired effect when an error occurs, in my case it changes the background color of the field red, you can change it to whatever effect you want without it interfering with your field CSS classes…perfect!


Aug 11 2007

My first post

etienne @ 12:06 pm

I’ve been wanting to setup a blog for a long time but never quite got around to it, until now. I’m using WordPress as it was compatible with the components on my host server, and seems very popular. It was simple to setup and install, I’m using a wonderful template developed by Tommaso Baldovino. I originally looked at  mephisto but the server that hosts this blog did not have the required components. I’ve installed a few plugins while I was setting it all up including:

I work as a freelance developer using a number of development tools including C++, PHP, Ruby, and Rails.

Tag: Rails, Ruby

« Previous Page