Rails how to beautify this block - ruby-on-rails

kinda new to Rails.
How would you simplify, beautify this method:
def find_index
index = 0
#ipn.each {|p|
index = 4 if p = "new" #this is just a dummy line
}
index
end
As you can see, it's ugly. How can I remove the index definition at the top and the index at the bottom to return - The Ruby way?

I think you want this method:
http://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-find_index
def find_index
#ipn.find_index{|p| p == "new" }
end
I also change the variable name '#ipn' to '#ipns', since it seems to be an enumerable.
And to avoid confusion, I might rename the method to 'find_ipn_index', so it looks like this:
def find_ipn_index
#ipns.find_index{|p| p == "new" }
end
Or, if self.ipns is available, don't define a new method at all for this, just call:
self.ipns.find_index{|p| p == "new" }

Related

array.select not iterating through every element

I have a rails controller and this code only loop through the first element in the metrics array? Why is that?
# /metrics/:id
def values
#metric = metrics.select do |metric|
id = metric['href'].split('/').last
p "id == params[:id] = #{id == params[:id]}" # false on the first iteration (but never gets to the next iteration
return id == params[:id]
end
p "HERE?" # We never get here!
end
You need to remove the return statement from your method, Ruby uses implicit return (see https://jtrudell.github.io/blog/ruby_return_values/), so the result of a block is the last line that is evaluated in that block, the return statement in your code is treated as a return from the values method. Your method needs to look something like:
def values
#metric = metrics.select do |metric|
metric['href'].split('/').last == params[:id]
end
end

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

Put specific collection/array item on the last position in rails

I have a collection/array in rails, transformed to json it looks like this:
#collection = [{"order_number":"123","item":"Paper"},{"order_number":"567","item":"Ruler"},{"order_number":"344","item":"Pen"},{"order_number":"342","item":"Pencil"},{"order_number":"877","item":"Keyboard"}]
I would like to pick the item with the order_number "342" and put it at the last position of the collection, so the new collection looks like this:
#collection = [{"order_number":"123","item":"Paper"},{"order_number":"567","item":"Ruler"},{"order_number":"344","item":"Pen"},{"order_number":"877","item":"Keyboard"},{"order_number":"342","item":"Pencil"}]
In theory, it would look like this:
#collection.last = #collection[3]
but that is obviously not fancy ruby style nor would it re-sort the array as in my example.
Also I don't know the index of the item as it can change depending on what the user shops.
how about:
#collection << #collection.delete_at[#collection.index{|x| x[:order_number] == "342"}]
This basically searches the index of element with :order_number 342 first, uses that index to delete it, and then store the deleted element at the end again.
You can also use the partition method:
#collection = #collection.partition { |h| h['order_number'] != '342' }.flatten
Just split your collection on two (without 342 order and with 342 order), then just join them. It should looks like:
#collection = #collection.select {|e| e[:order_number] != '342' } + #collection.select {|e| e[:order_number] == '342' }
If you have an index of an item it boils down to
#collection << #collection.delete_at(3)
If you don't, you could try finding it using
#collection.find_index{ |el| el["order_number"] == "123" }
Alternative you can try this too:
> #collection.each_with_index{ |key,value| #collection.push(#collection.delete_at(value)) if key[:order_number] == "344" }
#=>[{:order_number=>"123", :item=>"Paper"}, {:order_number=>"567", :item=>"Ruler"}, {:order_number=>"342", :item=>"Pencil"}, {:order_number=>"877", :item=>"Keyboard"}, {:order_number=>"344", :item=>"Pen"}]

Filter controller result based on params

I'm trying to filter the results that are returned from my index view based on optional params. My code is working for the first param, sinceDate. But for the second param, searchQeury, nothing is filtered out.
_controller.rb
def index
since = params[:sinceDate]
query = params[:searchQuery]
#articles = Comfy::Cms::Page.published.all
if since
#articles = #articles.reject{ |a| a[:created_at] < Date.parse(since) }
end
if query
#article = #articles.select{ |a| a[:label].match(/#{query}/i) }
end
end
Is it possible that the problem is a typo?
In the line after "if query", it should be perhaps #articles instead of #article.

Resources