Move method from the view in the model - ruby-on-rails

In the view I want to display the total balance. I do it that way.
controller:
def index
#invoices = Invoice.balance
end
views:
.pull-right
strong The total balance:
= #invoices.map(&:balance).sum
I understand that it's wrong.
How can I move this method in the model?
def total_balance
Invoice.all.map(&:balance).sum
end
If you do so, then how to use in the view?

You should write a class method:
def self.total_balance
sum(:balance)
end
And then simply call it in your view on the invoices collection:
= #invoices.total_balance

Related

Rails complicated class method chaining

How do you write a complicated class method that applies to whatever it's being chained to? Let me explain: a simple class method such as:
def self.despondent
where(despondent: true)
end
can be easily chained:
User.desperate.despondent.disillusioned
But what if you've got a complicated class method such as:
def self.friendly_dogs(user)
#dogs1 = Dog.none
#dogs2 = Dog.none
if user.has_dog
users = User.friends.where(has_dog: true)
#dogs1 = Dog.where(user_id: users.ids)
end
if user.wife.has_dog
users = user.wife.friends.where(has_dog: true)
#dogs2 = Dog.where(user_id: users.ids)
end
return #dogs1.or(#dogs2).distinct
end
How would you write this so you can place it anywhere in the chain? And in the following example would select only the friendly_dogs from all poodles that are 1 year old:
#dogs = Dog.where(breed: "poodle").where(age: "1").friendly_dogs.paginate(page: params[:page])

ROR: Creating a method with a parameter

I have an admins dashboard which displays posts created in the last 24 hours, 7 days, 28 days etc.
def index
#1DayPosts = Post.where(created_at: 1.days.ago..DateTime.now).count
#7DaysPosts = Post.where(created_at: 7.days.ago..DateTime.now).count
#28DaysPosts = Post.where(created_at: 28.days.ago..DateTime.now).count
end
How could I make this into one line? Something like the below:
def index
#calculatePosts(a) = Post.where(created_at: a.days.ago..DateTime.now).count
end
Then in the view I could do:
=#calculatePosts(1)
Or would I need to create a new method?
def calculatePosts(a)
#calculatePost = Post.where(created_at: a.days.ago..DateTime.now).count
end
How would I then call this in the index view?
Your best bet would be to create a scope on the Post model.
class Post ...
scope :last_x_days, -> (x) { where(created_at: x.days.ago..Time.zone.now) }
end
Then you can call that anywhere really, in your view or controller like this.
#last_10_days = Post.last_x_days(10).count
EDIT:
You could do this also, but scopes are meant to be chain-able, so this is discouraged, though not wrong.
scope :last_x_days_count, -> (x) { where(created_at: x.days.ago..Time.zone.now).count }

rails controller map unknown

In authors_controller.rb, I have this :
def show
a = Author.find(params[:id])
#author = a.map { |e| e.titlecase }
end
I get an error say that map is an undefined method for Author::0x007fec244142a0.
I also tried this :
def show
#author = Author.find(params[:id])
#author.each { |k, v| v.capitalize }
end
How can I apply the method titlecase to each value of Author.find ?
find(params[:id]) returns not array, not enumerator and not Relation class but just instance of your model. You can't use map or each so just apply titlecase to returned object.
def show
#author = Author.find(params[:id])
#author.name = #author.name.titlecase # if you have column 'name'
end
But better move titlecased name to model's method or just use #author.name.titlecase where it's needed.
You can use where and use map operator with it:
def show
#author = Author.where(id: params[:id])
It's ugly but it works. I'm sure there is a better way to do this stuff.
#author.attributes.map do |k,v|
v = #author.__send__(k).capitalize if #author.__send__(k).respond_to?(:capitalize)
end
#author.save
I must say however that I wouldn't recommend doing things this way. Better to capitalize each field in the model
From I understood. You want to capitalize all fields of record Author.find(params[:id]) right?
First, Author.find(params[:id]) will return a record, not array. That means you can't use each or map for it.
To capitalize all fields of a record. Could u try:
def show
author = Author.find(params[:id])
#author = author.attributes.values.map{|field| field.to_s.capitalize}
end
It will return an array of all field values.
UPDATE 1
For better
def show
author = Author.find(params[:id])
#author_info = author.attributes.values.map{|field| field.is_a?(String) ? field.capitalize : field}
end

How to get all records of all parent records

I'm needing to create a select box for a form where I list all child records of all parents. How do I do this in my controller? I'm thinking the answer below, but its returning "undefined method nil:NilClass"
before_action :get_children
def get_children
#parents = current_user.parents.all
#children = #parents.children.all
end
#parents is an array so the children of that array would be nil.
So you would have to use some type of loop like:
def get_children
children = []
#parents = current.user.parents.all
#parents.each do |child|
children << child
end
return children
end
Something like this oughta work.
If you want an array:
#children = #parents.map(&:children).flatten.uniq
If you want an ActiveRecord::Relation (assuming your model is called Thing, and each thing belongs_to parent):
#children = Thing.where(parent_id: #parents)
You can do the following:
def get_children
#parents = current_user.parents.all
#children = Children.where(parent_id: #parents.pluck(:id).uniq)
end

better way to build association in controller

I need a link in a show method of a parent class for creating associated models, so I have the code:
link_to "incomplete", new_polymorphic_path(part_c.underscore, :survey_id => survey.id)
in a helper.
This links to a part, which has new code like this:
# GET /source_control_parts/new
def new
get_collections
if params[:survey_id]
#s = Survey.find(params[:survey_id])
if #s.blank?
#source_control_part = SourceControlPart.new
else
#source_control_part = #s.create_source_control_part
end
else
#source_control_part = SourceControlPart.new
end
end
I know this is not very DRY. How can I simplify this? Is there a RAILS way?
How about this:
def new
get_collections
get_source_control_part
end
private
def get_source_control_part
survey = params[:survey_id].blank? ? nil : Survey.find(params[:survey_id])
#source_control_part = survey ? survey.create_source_control_part : SourceControlPart.new
end

Resources