How would you tidy up this controller logic? - ruby-on-rails

I've got some logic in a controller that sets a status of an object if certain conditions are met:
if params[:concept][:consulted_legal] == 0 && params[:concept][:consulted_marketing] == 1
#concept.attributes = {:status => 'Awaiting Compliance Approval'}
elsif params[:concept][:consulted_marketing] == 0 && params[:concept][:consulted_legal] == 1
#concept.attributes = {:status => 'Awaiting Marketing Approval'}
elsif params[:concept][:consulted_marketing] == 0 && params[:concept][:consulted_legal] == 0
#concept.attributes = {:status => 'Awaiting Marketing & Legal Approval'}
else
#concept.attributes = {:status => 'Pending Approval'}
end
that I share between create and update actions. How would you go about refactoring this nastiness? Looking for best practices.
New to programming and keen to clean up my code.
TIA.

You can make your code less dependent on both conditions and make it a lot more flexible.
waiting_on = []
waiting_on << 'Compliance' unless params[:concept][:consulted_marketing]
waiting_on << 'Legal' unless params[:concept][:consulted_legal]
status = waiting_on.empty? ? "Awaiting #{waiting_on.join(' & ')} Approval" : 'Pending Approval'
#concept.attributes = {:status => status}
Version for both create and update without filter:
def create
set_concept_status_attribute
...
end
def update
set_concept_status_attribute
...
end
private
def set_concept_status_attribute
waiting_on = []
waiting_on << 'Compliance' unless params[:concept][:consulted_marketing]
waiting_on << 'Legal' unless params[:concept][:consulted_legal]
status = waiting_on.empty? ? "Awaiting #{waiting_on.join(' & ')} Approval" : 'Pending Approval'
#concept.attributes = {:status => status}
end
Or with a before_filter:
before_filter :set_concept_status_attribute, :only => [:create, :update]
def create
...
end
def update
...
end
If you can move it to you view, it looks even better:
module ConceptHelper
def get_concept_status
...
end
end
<%= get_concept_status %>

This is my take on it. I call it Super DRY.
statuses =
[
['Awaiting Marketing & Legal Approval','Awaiting Compliance Approval'],
['Awaiting Marketing Approval','Pending Approval']
]
{:status => statuses[params[:concept][:consulted_legal].to_i][params[:concept][:consulted_marketing].to_i]}
Alternatively, a more conventional approach -- lengthy but readable:
status = if params[:concept][:consulted_legal] == "0"
if params[:concept][:consulted_marketing] == "1"
'Awaiting Compliance Approval'
else
'Awaiting Marketing & Legal Approval'
end
else
if params[:concept][:consulted_marketing] == "0"
'Awaiting Marketing Approval'
else
'Pending Approval'
end
end
#concept.attributes = {:status => status}
Note: It looks like your original code is checking values of check boxes. Values in the params hash are always Strings, not Fixnums so my code compares strings. If for some reason comparing Fixnums is what is required for your situation, just take out the quotes around the numbers.

That looks to be business logic, so it should be in the model really.
Your model probably needs a couple of attributes: consulted_legal and consulted_marketing, and a method to set the status when either one of them is changed something like this:
before_update :set_status
def set_status
if consulted_legal && consulted_marketing
status = "Pending Approval"
elif consulted_legal && !consulted_marketing
status = "Awaiting Marketing Approval"
elif !consulted_legal && consulted_marketing
status = "Awaiting Legal Approval"
elif !consulted_legal && !consulted_marketing
status "Awaiting Marketing & Legal Approval"
end
true # Needs to return true for the update to go through
end

Break it down into nested if statements.
if params[:concept][:consulted_legal] == '0'
if params[:concept][:consulted_marketing] == '1'
#concept.attributes = { :status => 'Awaiting Compliance Approval' }
else
#concept.attributes = { :status => 'Awaiting Marketing & Legal Approval' }
end
else
if params[:consulted_marketing] == '1'
#concept.attributes = { :status => 'Awaiting Marketing Approval' }
else
#concept.attributes = { :status => "Pending Approval" }
end
end

you may think the list of departments consulted is a fixed enough concept to justify variables named consulted_marketing etc.. But for growth, and dryness (in a way), Id prefer a list of departments.
What you really have here is a workflow or state machine, I think a list of deparments with transitions would result in the cleanest, most growable code.
Code is data ! Model your data and the code will be trivial.

This looks like a business rule to me. As such you might want to wrap it into a function:
string GetConceptStatus(bool consulted_legal, bool consulted_marketing)
{
if (consulted_legal && consulted_marketing) {
return "Pending Approval";
}
if (consulted_legal && !consulted_marketing) {
return "Awaiting Marketing Approval";
}
if (!consulted_legal && consulted_marketing) {
return "Awaiting Legal Approval";
}
if (!consulted_legal && !consulted_marketing) {
return "Awaiting Marketing & Legal Approval";
}
}
This also separates the details of how bools are encoded in your interface from the actual implementation of the business rule.
But the actual structure of the code looks good to me, since it probably better models the business rule.

Related

How to simplify big conditions

I have five dropdowns, and I need to put conditions on each of them. My code is:
def search(search, compare, year, rain_fall_type)
if search == 'All'
if rain_fall_type == 'All'
all
else
if year == 'All'
if rain_fall_type == "None"
where('Sector = ? OR Sector = ? OR Sector = ?', "Primary", 'Secondary', 'Tertiary').order('id')
else
# all
where(Sector: rain_fall_type).order('id')
end
else
if rain_fall_type == "All"
order("#{year} ")
elsif rain_fall_type == "None"
where('Sector = ? OR Sector = ? OR Sector = ?', "Primary", 'Secondary', 'Tertiary').order('id')
else
where(Sector: rain_fall_type).order("#{year} ")
end
end
# where(Year: year).order("#{rain_fall_type} ")
end
elsif compare != "None"
if year == 'All'
where('Sector = ? OR Sector = ?', rain_fall_type, compare).order(:id)
else
where('Sector = ? OR Sector = ?', rain_fall_type, compare).order(:id)
end
else
if rain_fall_type == 'All'
all.order('id')
else
if year == 'All'
if rain_fall_type == "None"
where('Sector = ? ', search).order('id')
else
where('Sector = ? ', rain_fall_type).order('id')
end
else
if rain_fall_type == "None"
if search == "All"
where('Sector = ? ', search).order('id')
else
where('Sector = ? ', search).order('id')
end
else
# all
where('Sector = ? ', rain_fall_type).order('id')
end
end
end
end
end
It has many if and else. I am trying to minimise the conditions. What can be the best way to shrink this code? Someone suggested that I should use switch case instead. Should I use it? If so, how?
You can use a guard statement which is basically return something if some_condition?. This only doable in specific scenarios (where one of the condition is executing a single statement:
Bad example:
if condition?
do_something
else
do_something_else
end
This could be written as:
return do_something if condition?
do_something_else
This will give you less code branching.
Also, another recommendation is to call another method with more conditions instead of nesting conditions in one single shot.
Bad example:
if condition?
if condition_two?
do_something_two
else
do_something
end
else
do_something_else
end
This could be written as:
if condition?
call_another_method
else
do_something_else
end
def call_another_method
if condition_two?
do_something_two
else
do_something
end
end
An example from your code could be:
if rain_fall_type == 'All'
all
else
if year == 'All'
if rain_fall_type == "None"
where('Sector = ? OR Sector = ? OR Sector = ?', "Primary", 'Secondary', 'Tertiary').order('id')
else
# all
where(Sector: rain_fall_type).order('id')
end
else
if rain_fall_type == "All"
order("#{year} ")
elsif rain_fall_type == "None"
where('Sector = ? OR Sector = ? OR Sector = ?', "Primary", 'Secondary', 'Tertiary').order('id')
else
where(Sector: rain_fall_type).order("#{year} ")
end
end
end
That could be converted to:
return all if rain_fall_type == 'All'
if year == 'All'
return where('Sector = ? OR Sector = ? OR Sector = ?', "Primary", 'Secondary', 'Tertiary').order('id') if rain_fall_type == "None"
where(Sector: rain_fall_type).order('id')
else
return order("#{year} ") if rain_fall_type == "All"
return where('Sector = ? OR Sector = ? OR Sector = ?', "Primary", 'Secondary', 'Tertiary').order('id') if rain_fall_type == "None"
where(Sector: rain_fall_type).order("#{year} ")
end
I hope this could help :)
NOTE: This is to answer the original question of How to simplify big conditions?. But the original post is not following Rails/Ruby way of doing search and filters and not making a good use of scopes.
This is probably the best explanation of how you should set this up.
class Product < ActiveRecord::Base
# custom_scope_1
scope :status, -> (status) { where status: status }
# custom_scope_2
scope :location, -> (location_id) { where location_id: location_id }
# custom_scope_3
scope :search, -> (name) { where("name like ?", "#{name}%")}
end
def index
#products = Product.where(nil) # creates an anonymous scope
#products = #products.status(params[:status]) if params[:status].present?
#products = #products.location(params[:location]) if params[:location].present?
#products = #products.search(params[:search]) if params[:search].present?
end
This can be cleaned up further by...
def index
#products = Product.where(nil)
filtering_params(params).each do |key, value|
#products = #products.public_send(key, value) if value.present?
end
end
private
# A list of the param names that can be used for filtering the Products
def filtering_params(params)
params.slice(:status, :location, :search)
end
This method uses ruby meta-programming to loop through parameters and dynamically call predefined scopes on a model
You can move this code into a module and include it into any model that supports filtering
app/models/concerns/filterable.rb
module Filterable
extend ActiveSupport::Concern
module ClassMethods
def filter(filtering_params)
results = self.where(nil)
filtering_params.each do |key, value|
results = results.public_send(key, value) if value.present?
end
results
end
end
end
app/models/product.rb
class Product
include Filterable
...
end
app/controllers/product_controller.rb
def index
#products = Product.filter(params.slice(:status, :location, :search))
end
You now have filtering and searching of your models with one line in the controller and one line in the model
First of all, some of your logic doesn't make sense:
def search(search, compare, year, rain_fall_type)
if search == 'All'
if rain_fall_type == 'All'
all
else
# rain_fall_type != 'All'
if year == 'All'
if rain_fall_type == "None"
where('Sector = ? OR Sector = ? OR Sector = ?', "Primary", 'Secondary', 'Tertiary').order('id')
else
where(Sector: rain_fall_type).order('id')
end
else
# in rain_fall_type != 'All' branch, so meaningless 'if'
if rain_fall_type == "All"
order("#{year} ")
elsif rain_fall_type == "None"
where('Sector = ? OR Sector = ? OR Sector = ?', "Primary", 'Secondary', 'Tertiary').order('id')
else
where(Sector: rain_fall_type).order("#{year} ")
end
end
end
elsif compare != "None"
# both are same, so meaningless 'if'
if year == 'All'
where('Sector = ? OR Sector = ?', rain_fall_type, compare).order(:id)
else
where('Sector = ? OR Sector = ?', rain_fall_type, compare).order(:id)
end
else
# search != 'All'
if rain_fall_type == 'All'
all.order('id')
else
if year == 'All'
if rain_fall_type == "None"
where('Sector = ? ', search).order('id')
else
where('Sector = ? ', rain_fall_type).order('id')
end
else
if rain_fall_type == "None"
# in search != 'All' branch, so meaningless 'if'
# AND both are same, so again meaningless 'if'
if search == "All"
where('Sector = ? ', search).order('id')
else
where('Sector = ? ', search).order('id')
end
else
where('Sector = ? ', rain_fall_type).order('id')
end
end
end
end
end
There's more like that and I won't point it all out because we're throwing all that if stuff out, anyway.
Ultimately, we're going to defer the querying to the end of the method, like this:
def search(search, compare, year, rain_fall_type)
...
#query = all
#query = #query.where(Sector: #sectors) if #sectors
#query = #query.order(#order) if #order
#query
end
That way, you take all of your where and order statements, and do them only once at the end. That saves a lot of typing right there. See the comment from muistooshort for why (Sector: #sectors) works.
So, the trick is setting #sectors and #order. First, I'm going to assign the input variables to instance variables because I like it like that (and to avoid confusion between the variable #search and the method search):
def search(search, compare, year, rain_fall_type)
#search, #compare, #year, #rain_fall_type = search, compare, year, rain_fall_type
...
#query = all
#query = #query.where(Sector: #sectors) if #sectors
#query = #query.order(#order) if #order
#query
end
Now, this answer is going on too long already, so I won't drag you through all the gorey details. But, adding in a couple of helper methods (sectors_to_use, and order_to_use) and substituting them in for #sectors and #order, you basically end up with this:
def search(search, compare, year, rain_fall_type)
#search, #compare, #year, #rain_fall_type = search, compare, year, rain_fall_type
#query = all
#query = #query.where(Sector: sectors_to_use) if sectors_to_use
#query = #query.order(order_to_use) if order_to_use
#query
end
private
def sectors_to_use
return [#rain_fall_type, #compare] if #search != 'All' && #compare != 'None'
unless #rain_fall_type == 'All'
if #rain_fall_type == 'None'
#search == 'All' ? ['Primary', 'Secondary', 'Tertiary'] : [#search]
else
[#rain_fall_type]
end
end
end
def order_to_use
return nil if (#search == 'All') && (#rain_fall_type == 'All')
return #year if (#search == 'All') && !(#year == 'All')
return :id
end
That's less than half the lines of code, over a thousand fewer characters, and a whole lot fewer ifs.

Why are Rails cookies disappearing in Functional Tests

In my Application Controller I am setting cookies in 3 places. In a before filter...
def set_abingo_identity
# skip bots
if request.user_agent =~ /#{#robot_regular_expression}/i
Abingo.identity = "robot"
elsif current_user
Abingo.identity = cookies[:abingo_identity] ||=
{ :value => current_user.id, :expires => 1.year.from_now }
else
Abingo.identity = cookies[:abingo_identity] ||=
{ :value => rand(10 ** 10), :expires => 1.year.from_now }
end
end
... and in two methods...
def remember_visit url
20.times do |i|
# Add cookie to referrer list
name = "referrer#{i}"
if cookies[name].blank?
cookies[name] = {:value => url, :expires => Time.now + 1.year }
break
elsif cookies[name] == url
break # skip
end
end
end
... and this one...
def set_referral_cookie val
ref_name = "referral_id"
offer_name = "offer_id"
cur = cookies[ref_name]
offer = cookies[offer_name]
affiliate = Affiliate.find_by_name val
if cur.blank? || offer.blank?
if affiliate
if cur.blank?
cookies[ref_name] = { :value => affiliate.id.to_s, :expires => Time.now + 1.year }
end
if offer.blank? && affiliate.offer? && !affiliate.expired?
cookies[offer_name] = { :value => affiliate.id.to_s, :expires => Time.now + 1.year }
end
end
end
return affiliate
end
Stepping through in the debugger, I see in the before filter, cookies["abingo_identity"] is set. Then in remember_visit(), both it and cookies["referrer0"] are set, and then in set_referral_cookie(), all 3 are set.
But when I get back to my functional test, only cookies["abingo_identity"] is set.
The cookies["abingo_identity"] part is new, and when I comment it out, the other cookies persist.
What is wrong with this code?
Update:
They are not getting deleted, but they are not all copied to the test case's #response.cookies

Is it okay to have a method in the before block of a series of RSpec unit tests?

I have a pretty elaborate set-up to change the condition from passing to failing for four composing methods of a method called eligible?.
describe "#participant_age_eligible?" do
it "returns whether participant is age-eligible" do
#part.participant_age_eligible?(#pers).should == true
end
it "returns false if participant is not age eligible" do
q = #survey_section.questions.select { |q| q.data_export_identifier ==
"#{OperationalDataExtractor::PbsEligibilityScreener::
INTERVIEW_PREFIX}.AGE_ELIG" }.first
answer = q.answers.select { |a| a.response_class == "answer" && a.reference_identifier == "2" }.first
Factory(:response, :survey_section_id => #survey_section.id, :question_id => q.id, :answer_id => answer.id, :response_set_id => #response_set.id)
#part.participant_age_eligible?(#pers).should == false
end
end
describe "#participant_psu_county_eligible?" do
it "returns whether participant lives in eligible PSU" do
#part.participant_psu_county_eligible?(#pers).should == true
end
it "returns false if participant coes not live in an eligible PSU" do
q = #survey_section.questions.select { |q| q.data_export_identifier ==
"#{OperationalDataExtractor::PbsEligibilityScreener::
INTERVIEW_PREFIX}.PSU_ELIG_CONFIRM" }.first
answer = q.answers.select { |a| a.response_class == "answer" && a.reference_identifier == "2" }.first
Factory(:response, :survey_section_id => #survey_section.id, :question_id => q.id, :answer_id => answer.id, :response_set_id => #response_set.id)
#part.participant_psu_county_eligible?(#pers).should == false
end
end
There are two more methods just like those two. What I'd like to do is extract the
q = #survey_section.questions.select { |q| q.data_export_identifier ==
"#{OperationalDataExtractor::PbsEligibilityScreener::
INTERVIEW_PREFIX}.AGE_ELIG" }.first
answer = q.answers.select { |a| a.response_class == "answer" && a.reference_identifier == "2" }.first
Factory(:response, :survey_section_id => #survey_section.id, :question_id => q.id, :answer_id => answer.id, :response_set_id => #response_set.id)
portion into a method in the before block and then pass the relevant parameters, but I hesitiate because I have never seen someone define a method in a before block, not even sure you can do it, further, I'm not sure if you even should do it even if you can, maybe it's pointing to a problem that I'm not seeing. So I though I'd ask the unfathomably enormous expertise of the SO community. Thanks.
You can always define methods within your specific rspec file, and then call them from anywhere in that file. For example:
# your_file_spec.rb
describe MyModel do
before(:each) { setup_variables }
describe ...
end
# I usually put my helper methods at the bottom
def setup_variables
# Do some work
end
end
You can also sometimes use a 'scenario outline' approach to your work, for example:
# your_file_spec.rb
describe MyModel do
examples = [{:name => "Joe", :login => "joe18"}, {:name => "Grace", :login => "grace12"}]
examples.each do |example|
it "logs in #{example[:name]}." do
# Do some work
end
end
end
You may also find that useful.

Making a fat controller in rails 3 skinny

I have this terribly large controller in my app. I'd really like to make it as skinny as possible. Below is some of the code, showing the types of things I'm currently doing.. I'm wondering what things I can move out of this?
A note - this is not my exact code, a lot of it is similar. Essentially every instance variable is used in the views - which is why I dont understand how to put the logic in the models? Can models return the values for instance variables?
def mine
#For Pusher
#push_ch = "#{current_user.company.id}"+"#{current_user.id}"+"#{current_user.profile.id}"
#Creating a limit for how many items to show on the page
#limit = 10
if params[:limit].to_i >= 10
#limit = #limit + params[:limit].to_i
end
#Setting page location
#ploc="mine"
#yourTeam = User.where(:company_id => current_user.company.id)
#Set the user from the param
if params[:user]
#selectedUser = #yourTeam.find_by_id(params[:user])
end
#Get all of the user tags
#tags = Tag.where(:user_id => current_user.id)
#Load the user's views
#views = View.where(:user_id => current_user.id)
if !params[:inbox]
#Hitting the DB just once for all the posts
#main_posts = Post.where(:company_id => current_user.company.id).includes(:status).includes(:views)
#main_posts.group_by(&:status).each do |status, posts|
if status.id == #status.id
if #posts_count == nil
#posts_count = posts
else
#posts_count = #posts_count + posts
end
elsif status.id == #status_act.id
if #posts_count == nil
#posts_count = posts
else
#posts_count = #posts_count + posts
end
end
end
if params[:status] == "All" || params[:status] == nil
#posts = Post.search(params[:search]).status_filter(params[:status]).user_filter(params[:user]).order(sort_column + " " + sort_direction).where(:company_id => current_user.company.id, :status_id => [#status.id, #status_act.id, #status_def.id, #status_dep.id, #status_up.id]).limit(#limit).includes(:views)
else
#posts = Post.search(params[:search]).status_filter(params[:status]).user_filter(params[:user]).order(sort_column + " " + sort_direction).where(:company_id => current_user.company.id).limit(#limit).includes(:views)
end
elsif params[:inbox] == "sent"
#yourcompanylist = User.where(:company_id => current_user.company.id).select(:id).map(&:id)
#yourcompany = []
#yourcompanylist.each do |user|
if user != current_user.id
#yourcompany=#yourcompany.concat([user])
end
end
if params[:t]=="all"
#posts = Post.search(params[:search]).status_filter(params[:status]).user_filter(params[:user]).tag_filter(params[:tag], current_user).order(sort_column + " " + sort_direction).where(:user_id => current_user.id).includes(:views, :tags).limit(#limit)
elsif params[:status]!="complete"
#posts = Post.search(params[:search]).status_filter(params[:status]).user_filter(params[:user]).tag_filter(params[:tag], current_user).order(sort_column + " " + sort_direction).where(:user_id => current_user.id).includes(:views, :tags).limit(#limit)
elsif params[:status]!=nil
#posts = Post.search(params[:search]).status_filter(params[:status]).user_filter(params[:user]).tag_filter(params[:tag], current_user).order(sort_column + " " + sort_direction).where(:user_id => current_user.id).includes(:views, :tags).limit(#limit)
end
end
respond_to do |format|
format.html # index.html.erb
format.js # index.html.erb
format.xml { render :xml => #posts }
end
end
You can start by moving logic into the model...
A line like this screams of feature envy:
#push_ch = "#{current_user.company.id}"+"#{current_user.id}"+"#{current_user.profile.id}"
I would recommend moving it into the model:
#user.rb
def to_pusher_identity
"#{self.company_id}#{self.id}#{self.profile_id}"
end
And then in your controller
#push_ch = current_user.to_pusher_identity
At this point you could even move this into a before_filter.
before_filter :supports_pusher, :only => :mine
Another thing you can do is create richer associations, so you can express:
#tags = Tag.where(:user_id => current_user.id)
as
#tags = current_user.tags
Another example would be for main posts, instead of
Post.where(:company_id => current_user.company.id).includes(:status).includes(:views)
you would go through the associations:
current_user.company.posts.includes(:status).includes(:views)
When I'm drying out a controller/action I try to identify what code could be (should be?) offloaded into the model or even a new module. I don't know enough about your application to really point to where these opportunities might lie, but that's where I'd start.
Few quick ideas:
Consider using respond_to/respond_with. This controller action can be splitted up to two separate ones - one for displaying #main_posts, another for params[:inbox] == "sent". The duplicate code can be removed using before_filters.
Also, a couple of gem suggestions:
use kaminari or will_paginate for pagination
meta_search for search and sorting

Trying to use current_user where it is undefined

I have this call in my vote model:
fires :vote_updated, :on => :update,
:actor => :user,
:secondary_subject => :video,
:if => lambda { |vote| ((vote.value == 1) || (vote.value == -1)) && (vote.video.user != current_user)}
In case you aren't familiar, it works with the timeline_fu plugin.
I do not want the call to be fired if the user who owns the voted up video is the current user. That is where this line comes in:
:if => lambda { |vote| ((vote.value == 1) || (vote.value == -1)) && (vote.video.user != current_user)}
However, I do not have access to current_user here. How do I get around this?
Here's the create method in my votes controller (there actually is no update method):
def create
#video = Video.find(params[:video_id])
#vote = current_user.video_votes.find_or_create_by_video_id(#video.id)
if #vote.value.nil?
if params[:type] == "up"
#vote.value = 1
else
#vote.value = -1
end
elsif (params[:type] == "up" && #vote.value == 1) || (params[:type] == "down" && #vote.value == -1)
#vote.value = 0
elsif ((params[:type] == "up" && #vote.value == -1) || (params[:type] == "down" && #vote.value == 1)) || (#vote.value == 0)
if params[:type] == "up"
#vote.value = 1
else
#vote.value = -1
end
end
if #vote.save
respond_to do |format|
format.html { redirect_to #video }
format.js
end
else
respond_to do |format|
format.html
format.js
end
end
end
I believe the right thing to do would be validating this in controller. I would create a before filter for this case
UPDATE:
Just as a quick example:
before_filter :valid_vote, :only => :update
def update
#vote.update_attributes(params[:vote]) # or whatever
end
..
private
def valid_vote
#vote = Vote.find params[:id]
unless ( #vote.video.user.id != current_user.id )
render :text => 'You can't vote for your own video', :status => 403
end
end
So #vote is being declared and validated before your 'update' action is proccessed.
If it's not valid then your 'update' action stays untouched
UPDATE 2 :
not sure how you'll like it, but you could also do as follows:
in your Vote model:
attr_accessor :skip_timeline
then use the concept with before filter, but do #vote.skip_timeline = true instead of rendering text
then the statement might look as follows:
:if => lambda { |vote| ((vote.value == 1) || (vote.value == -1)) && !vote.skip_timeline }
You could also move ((vote.value == 1) || (vote.value == -1)) to your before filter :
def valid_vote
#vote = Vote.find params[:id]
unless ( [1,-1].include? #vote.value && #vote.video.user.id != current_user.id )
#vote.skip_timeline = true
end
end
and
:if => lambda { |vote| !vote.skip_timeline }
You are getting this error because it's typically not recommended to access current_user (or session information) in your model. I am not all that familiar with the timeline_fu gem, so this answer isn't going to be the greatest answer you may get. I'm merely going to show you how to access current_user from any model.
First go to your application controller. You'll want to make a method that sets the current user. You need to call the method in the before filter.
before_filter :loadCurrentUser
def loadCurrentUser
  User.currentUser = current_user
end
Then in your User model, you need to define 'currentUser'.
def self.currentUser
Thread.currentUser[:user]
end
You don't necessarily have to declare the current_user in the application controller, but since it's a gem, I'm not sure if it has an easily accessible controller.
Edit: This way may be prone to problems, but I'm not entirely sure if you were asking how to make current_user available in models, or a completely different workaround so you do not have that problem... and reading the responses of the other answer, I'm thinking it's not what you were asking.

Resources