Going Ajax |
Where to go from here ![]() |
Module Tutorial: User Polling / Rating: Remembering Users Choices
We’ve pretty much come to the end of the tutorial, but there’s one more thing that’s worth doing, to prevent ballot stuffing by remembering users’ choices. This is also a good example of iterating on a module, as we’ll need to do some fairly wide ranging changes across the breadth of the PollDemo module. Let’s break down the necessary steps before we get started:
- We need to add and run a new migration on the module to add a
user_idfield to the database (and probably an index on the user as well). - We need to modify our
PollDemoPollclass to pass theuser_idthrough. - We need to modify our renderer to store submitted polls in the session and check the database by id.
Let’s get started.
Step 1: Adding the new migration
Let’s add the new migration using the Webiva migration generator
$ ./script/generate webiva_module_migration PollDemo user_responses
Open up the migration file it created and add the following:
class UserResponses < ActiveRecord::Migration
def self.up
add_column :poll_demo_responses, :end_user_id, :integer
add_index :poll_demo_responses, :end_user_id
end
def self.down
remove_column :poll_demo_responses, :end_user_id
remove_index :poll_demo_responses, :end_user_id
end
end
Now let’s run the migration:
$ rake cms:migrate_domain_components COMPONENT=poll_demo
Step 2: Modifying the model
Let’s open up poll_demo_poll.rb and modify the add_response method to handle the user:
vendor/modules/poll_demo/app/models/poll_demo_poll.rb
def add_response(response,user=nil,ip=nil)
response = response.to_i
if response > 0 && response <= self.answers.length
if self.poll_demo_responses.create(:response => response,
:ip_address => ip,
:end_user => user)
recalculate_results!
end
else
false
end
end
We’ve added another argument for the user. We’ve also added a check on the return value of the create, in case there was a validation error.
Now we need to add a relation and validation to the EndUser model inside of poll_demo_response.rb:
vendor/modules/poll_demo/app/models/poll_demo_response.rb
belongs_to :end_user
validates_uniqueness_of :poll_demo_poll_id, :scope => :end_user_id
Step 3: Modifying the renderer
We need to do a couple of things:
Keep track of what polls a user has responded to in their session.
Check if a user is logged in and check the database if they have already responded.
We’ll accomplish these by adding a couple of protected methods into the renderer called already_responded? and add_saved_response, and modify the view method to use them. We need to add these to the renderer because only the renderer has access to the session and the myself object which represents the current user. Here’s some code that does the trick; you’ll want to replace the entire view method:
vendor/modules/poll_demo/app/controllers/poll_demo/page_renderer.rb
def view
@options = paragraph_options(:view)
if !params[:poll]
@poll = PollDemoPoll.random_poll
@response = @poll.poll_demo_responses.build if @poll
@state = already_responded?(@poll) ? 'responded' : 'question'
else
@poll = PollDemoPoll.find_by_id(params[:poll][:poll_demo_poll_id])
if already_responded?(@poll)
@state = 'responded'
elsif @poll && @poll.add_response(params[:poll][:response],myself,request.remote_ip)
@state = 'responded'
add_saved_response(@poll)
end
end
require_js('prototype')
render_paragraph :feature => :poll_demo_page_view
end
protected
def add_saved_response(poll)
session[:polls] ||= []
session[:polls] << poll.id unless session[:polls].include?(poll.id)
end
def already_responded?(poll)
session[:polls] ||= []
included = session[:polls].include?(poll.id)
if !included && myself.id
response =
PollDemoResponse.find_by_end_user_id_and_poll_demo_poll_id(myself.id,poll.id)
if response
included = true
session[:polls] << poll.id
end
end
included
end
Now give this a shot and see how it works. When you load the page, you shouldn’t see the question, only the response graph.
Going Ajax |
Where to go from here ![]() |

Going Ajax