ezweizig
ezweizig

Reputation: 27

Rails survey calculating results and storing results in DB

Having trouble with the controller of my survey (Waterusage). It has 30+ variables collected from a form and those inputs need to be saved to the waterusage db and used to calculate a final score, also saved in the database.

class Waterusage < ApplicationRecord
  belongs_to :user
end


class WaterusagesController < ApplicationController

  def new
    @waterusage = Waterusage.new
  end

  def create
    @user = User.find(params[:user_id])
    _showerTotal = :average_shower * :shower_flow_rate * :household_size
    _bathTotal = :bath_rate * :bath_multiplier * 35
    _bathroomSinkTotal = :bathroom_sink_usage * :bathroom_sink_flow_rate * :household_size
    _toiletTotal = :mellow * :low_flow_toilet * :household_size
    _kitchenTotal = :kitchen_sink_usage * :kitchen_sink_flow_rate
    _dishwashingTotal = :dishwasher_rate * :dishwasher_multiplier * :dishwasher_method
    _laundryTotal = :laundry_rate * :laundry_method * :laundry_multiplier
    _homeUsage = _showerTotal + _bathTotal + _bathroomSinkTotal + _toiletTotal + _kitchenTotal + _dishwashingTotal + _laundryTotal + :greywater
    _lawnTotal = :lawn_rate * :lawn_multiplier * :lawn_size * :xeriscaping
    _swimmingTotal = (:swimming_pool / 365) + (:swimming_months * 1000 / 365
    _carwashTotal = :carwash_rate * :carwash_multiplier * :carwash_method
    _outsideUsage = _lawnTotal + _swimmingTotal + _carwashTotal
    _drivingTotal = 0.735 * :miles
    _powerTotal = :statewater * :percent_statewater / 100
    _indirectTotal = :shopping + :paper_recycling + :plastic_recycling + :can_recycling + :textile_recycling + :diet + (200 * :pet_cost / 30)
    :household_total = _homeUsage + _outsideUsage + _drivingTotal + _powerTotal + _indirectTotal
    :individual_total = :household_total / :household_size
    @waterusage = @user.waterusage.create(waterusage_params)
    redirect_to user_path(@user)
  end

  def destroy
    @user = User.find(params[:user_id])
    @waterusage = @user.waterusage.find(params[:id])
    @waterusage.destroy
    redirect_to user_path(@user)
  end

  private
    def waterusage_params
      params.require(:waterusage).permit(:household_size, :average_shower,
        :shower_flow_rate, :bath_rate, :bath_multiplier, :bathroom_sink_usage,
        :bathroom_sink_flow_rate, :mellow, :low_flow_toilet, :kitchen_sink_usage,
        :kitchen_sink_flow_rate, :dishwasher_rate, :dishwasher_multiplier,
        :dishwasher_method, :laundry_rate, :laundry_multiplier, :laundry_method,
        :greywater, :lawn_rate, :lawn_multiplier, :lawn_size, :xeriscaping,
        :swimming_pool, :swimming_months, :carwash_rate, :carwash_multiplier,
        :carwash_method, :miles, :statewater, :percent_statewater, :shopping,
        :paper_recycling, :plastic_recycling, :can_recycling, :textile_recycling,
        :diet, :pet_cost, :individual_total, :household_total)
    end
end

Is there a better way I can be doing this? Currently there are errors on the lines that are working to sum subtotals. (ie. :household_total = _homeUsage + _outsideUsage + _drivingTotal + _powerTotal + _indirectTotal ) Also I'm not sure if I am properly connecting the user info to the survey schema

Upvotes: 0

Views: 41

Answers (2)

First of all prefix every ':' inside of create with a 'params[' and suffix ']', then change every '_' with a '@'.

It would be like this:

 _powerTotal = :statewater * :percent_statewater / 100 

turns into

 @powerTotal = params[:statewater].to_i * params[:percent_statewater].to_i /100

Like that,

 :individual_total = :household_total / :household_size  

turns into

 @individual_total = params[:household_total].to_i / params[:household_size].to_i

Also you're doing nothing with your calculations, they are just floating around, as it is, you can't even invoke them from your view.

If you want it to save on your waterusage object that relates to an user the individual_total attributes it would be;

@waterusage = @user.waterusage.create(waterusage_params, individual_total: @individual_total).

Upvotes: 0

Tom L
Tom L

Reputation: 3409

You don't want to do that math in the controller. Skinny controllers, fat models. Aside from that, one reason it's failing is that the syntax is incorrect. A symbol (:hello_world) can't be assigned a value nor does it contain one. Less importantly, while it's not illegal to have an underscore prefixed local variable, that is not the convention in Ruby. Neither is camelcase. You want hello_world rather than helloWorld. Anyway...

Assumption: You have a requirement that the totals must be persisted. They cannot be calculated values.

You want to move those calculations to the model. And instead of assigning a ton of variables, use methods. That way you can easily unit test them.

What's missing here: Validations in the model that ensure that all expected attribute values are present. The controller should handle an invalid Waterusage instance on create, too. This code is untested and is just for illustrative purposes.

class Waterusage < ApplicationRecord
  belongs_to user

  before_validation :calculate_totals

  def calculate_totals
    self.household_total = get_household_total
    self.individual_total = get_individual_total
  end

  def get_household_total
    home_usage + outside_usage + driving_total + power_total + indirect_total
  end

  def get_individual_total
    household_total / household_size
  end

  def home_usage
    shower_total + bath_total + bathroom_sink_total + toilet_total + kitchen_total + dishwashing_total + laundry_total + greywater
  end

  def outside_usage
    lawn_total + swimming_total + carwash_total
  end

  def driving_total
    0.735 * miles
  end

  def power_total
    statewater * percent_statewater / 100
  end

  def indirect_total
    shopping + paper_recycling + plastic_recycling + can_recycling + textile_recycling + diet + (200 * pet_cost / 30)
  end

  def shower_total
    average_shower * shower_flow_rate * household_size
  end

  def bath_total
    bath_rate * bath_multiplier * 35
  end

  def bathroom_sink_total
     bathroom_sink_usage * bathroom_sink_flow_rate * household_size
  end

  def toilet_total
    mellow * low_flow_toilet * household_size
  end

  def kitchen_total
    kitchen_sink_usage * kitchen_sink_flow_rate
  end

  def dishwashing_total
    dishwasher_rate * dishwasher_multiplier * dishwasher_method
  end

  def laundry_total
    laundry_rate * laundry_method * laundry_multiplier
  end

  def lawn_total
    lawn_rate * lawn_multiplier * lawn_size * xeriscaping
  end

  def swimming_total
    (swimming_pool / 365) + (swimming_months * 1000 / 365)
  end

  def carwash_total
    carwash_rate * carwash_multiplier * carwash_method
  end
end

class WaterusagesController < ApplicationController
  ...

  def create
    @user = User.find(params[:user_id])
    @waterusage = @user.waterusage.create(waterusage_params)
    redirect_to user_path(@user)
  end

  ...

end

Upvotes: 1

Related Questions