Sunday, March 21, 2010

doing a survey with ruby on rails (part 2)

Now, that the tables and models are setup, we implement the View and Controller layers. The scaffold has given already some start, but we'll change these to give our application a better survey character.

First, the index view of the questions. We want to see a simple list of questions that we have so far, and the associated choices.

So, let's edit this view in /survey/app/views/question/index.html.erb. We remove almost everything and replace it with a unlinked list in html like this:



Note how we have used a second unlinked list to display the choices that are associated with a question, and how the modify and destroy actions are removed to be accessible only from inside the question edit. The question can be edited by clicking on it.

At the moment, we don't have any choices yet in our database. Let's add some with putting "http://0.0.0.0:3000/choices" in the URL of our browser.

I add the following for now: "it's great", "much", "ok", "not much", "green", "blue", "red", "yellow"

Now, we arrive at one of the more difficult parts. Putting checkboxes in the new and edit views of the questions.

First, the new action in /survey/app/views/questions/new.html.erb :

We need to iterate over the choices. We can do this like this:




We also insert the loop in the edit view:




To have a short list in our show view on choices, we add in app/views/questions/show.html.erb:



So, that was part 2. By now, you should have a survey app where an administrator can easily enter questions and associate possible choices with these questions.

Next, we need to have users who can take part in the survey.


Saturday, March 20, 2010

doing a survey with ruby on rails (part 1)

This is a basic tutorial that might help you understand the basics of ruby-on-rails. The idea of the project comes from this stackoverflow.com question. My current rails working environment is 2.3.5.

As with every rails project, in the beginning rails gives you a basic project setup using the model-view-controller pattern.

Let's try:


./ > rails -d mysql survey


The -d option is important to specify the usage of a database right at the start. In general, I use mysql for this, and the provided database.yml may need a bit tweeking the first time, but will soon be functional for many rails projects.

To create and test the database, you want to check with:


./survey/ > rake db:create


if there is no error message.

Coming back to our MVC pattern, at the moment, the directories /survey/app/models, /survey/app/views and /survey/app/controllers are still empty.

Basic resources (what the combination of a view-model-controller often is), can easily be done with scaffolding.

So, let's make a resource for our "question" and one resource for a "choice".


script/generate scaffold question whatabout:string
script/generate scaffold choice desc:string


With


rake db:migrate


we create our new tables in the database.

Now, we need to associate a choice wih a question. We want to select the choices that a user can enter in the survey. So, we use a m:n relationship between choices and questions. (The steps behind this are explained more in detail here, here and here).

So, to implement the associations, we need to modify our table and the models accordingly.

First, we create a helper table with:

script/generate model questions_choice


In the new migration, we add references to our "choices" and "questions" tables like this:

class CreateQuestionsChoices < ActiveRecord::Migration
def self.up
create_table :choices_questions, :id => false do |t|
t.references :choice, :question
t.timestamps
end
end

def self.down
drop_table :choices_questions
end
end


Let's check that we have no problems so far with a:

rake db:migrate


Next, we edit our models:

We say:


# question.rb
class Question < ActiveRecord::Base
has_and_belongs_to_many :choices
end

# choice.rb
class Choice < ActiveRecord::Base
has_and_belongs_to_many :questions
end

# questions_choice.rb
class QuestionsChoice < ActiveRecord::Base
belongs_to :question
belongs_to :choice
end


As a result, we should be able to access the table "Questions" from the table "Choices", and vice versa. "belongs_to", "has_and_belongs_to_many" are method calls of ActiveRecord. In a sense, Ruby let defines us our own domain-specific language easily, and that is basically what Rails is.

To show that the models are working, it is helpful to check with the Ruby interpreter first. For this, we start:


./survey/ > script/console -s


The -s option says we want to use a sandbox, i.e. our modifications in the database are rollbacked after we exit from the console.

So, first

q = Question.new
q.whatabout="Our Rails tutorial"
q.save


gives us a first question where we can add choices to. We do this with


c = Choice.new(:desc => "it's ok")
q.choices << c


Ruby knows from our models how to set the foreign key question_id and choice_id in the join table by using the operator "<<". We can repeat editing and adding new choices for our first question database.

Within the console, we can list all our choices for a question with:


q.choices.each {|choice| puts "#{choice.id} #{choice.desc}"}



In the next part of the tutorial, we will have a look on how we can provide a user interface for our models on questions and choices