ROR: Creating a method with a parameter - ruby-on-rails

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 }

Related

How can i create concern method with different Class names (depending on Controller)

i have 2 controllers. Both are very similar, the difference is only the Model Class name.
For example:
production_controller.rb
def new_task_order_counter(board_id)
tasks = Production.where(board_id: board_id)
task_order = tasks.count + 1
end
development_controller.rb
def new_task_order_counter(board_id)
tasks = Development.where(board_id: board_id)
task_order = tasks.count + 1
end
I want to create a concern where there will be one method replacing both of these methods in my controllers. Is there way to get it?
Concern is the way to go
Create one in app/controllers/concerns:
module TasksConcern
extend ActiveSupport::Concern
included do
def new_task_order_counter(scope, board_id)
tasks = scope.where(board_id: board_id)
task_order = tasks.count + 1
# you could simplify to:
# scope.where(board_id: board_id).count + 1
end
end
end
To use it in your controller add this line:
include TasksConcern
And use the method like that:
order = new_task_order_counter(Development, board_id)

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])

Combine many scopes

I would like to combine two different scopes in my model. I have this:
Post_model
scope :with_tasks, -> { where(cat: 3).includes(:user).includes(task: :users) }
scope :with_events, -> { where(cat: 4).includes(:user).includes(event: :users) }
scope :with_comments, -> {where(comented: true).includes(comments: :user)}
Post_controller
def index
#posts = current_user.posts.with_tasks + current_user.posts.with_events
end
But I think it is not a really elegant way to achieve it, and I cannot include the comments scope.
Do you know a method to join this scopes into a new one (like the example below)?
scope :with_elements, -> { self.with_tasks.merge(self.with_events) }
What would allow me to call this method into my post#index:
#posts = current_user.posts.with_elements
TASKS = 3
EVENTS = 4
scope :with_tasks_and_or_events, ->(cat) {
cond = {}.tap do |c|
c.merge!(task: :users) if cat.include? TASKS
c.merge!(event: :users) if cat.include? EVENTS
end
where(cat: cat).includes(:user).includes(**cond)
}
And use it like:
with_tasks_and_or_events([TASKS])
with_tasks_and_or_events([TASKS, EVENTS])
Or, better, use Relational Algebra.
Or, even better, revise your database structure.

How can I iterate through a model then iterate again in my view?

I want to pull data for each of my users. I grab their person_id from my user table, then use each person's ID to figure out how many days each person has available, and show that in my view.
I'm not sure if I am doing this correctly because I am iterating in my controller then again in my view.
def how_many_days_users_have
#my_group = User.all.pluck(:person_id)
#my_group.each do |v|
#indirect_id_v = Empaccrl.where("person_id = ? and is_active = ?", '#{v]', 'Y').pluck(:a_code).first
#v_range = Empaccrl.where("person_id = ? and is_active = ?", '#{v]', 'Y').pluck(:ac).first
#v_range_taken = Empaccrl.where("person_id = ? and is_active = ?", '#{v]', 'Y').pluck(:taken).first
#total_v_hours = #v_range.to_d - #v_range_taken.to_d
#total_v_days = #total_v_hours / 8
end
Then in my view I use this to show me this data:
%tr.trace-table
-#indirect_id_v.each do |idd|
%tr.trace-table
%td.trace-table{:style => 'border: solid black;'}= idd
-#total_v_days.each do |days|
%tr.trace-table
%td.trace-table{:style => 'border: solid black;'}= days
Okay, first things first, move some of that junk to your model, like so:
class Empaccrl < ActiveRecord::Base
def self.all_people
where(person_id: User.all.pluck(:person_id))
end
def self.active_people
all_people.where(is_active: 'Y')
end
def self.active_vacation_data
active_people.select(:person_id, :ac, :taken)
end
def total_v_hours
ac.to_d - taken.to_d
end
def total_v_days
total_v_hours / 8
end
end
Then you can use:
peoples_vacation_information = Empaccrl.active_vacation_data.all
peoples_vacation_information.map do |person|
p "person #{person.person_id} has #{person.total_v_days} vacation days"
end
Honestly, you don't even need all that, but I'm not sure why you are doing what you are doing, so I figured better be safe and add stuff. Whatever you don't need, just ignore.

Move method from the view in the model

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

Resources