Array.select with optional conditionals - ruby-on-rails

I have an Array of Hashes
[
{ :user_id => 123,
:start_date => Date,
:end_date => Date
},
{ :user_id => 345,
:start_date => Date,
:end_date => Date
},
...
]
I want to select some of the objects based on optional parameters, say if params[:user_id], params[:start_date], params[:end_date] is optionally passed from the controller. How do I include multiple conditionals within a single .select statement.
Array.select do |arr|
arr[:user_id] == params[:user_id] if params[:user_id] &&
arr[:start_date] >= params[:start_date] if params[:start_date] &&
arr[:end_date] <= params[:end_date] if params[:end_date]
end
wasn't working as intended. The 2nd and 3rd conditional is ignored.

A pattern I like to use is next. This is basically a way to 'return early' from the block, and split up your conditions into multiple statements. Just make sure you add a true at the end so that if the item passes all the validations, it will be included in the result.
result = array.select do |item|
if params[:user_id]
next if item[:user_id] != params[:user_id]
end
if params[:start_date]
next if item[:start_date] <= params[:start_date]
end
if params[:end_date]
next if item[:end_date] >= params[:end_date]
end
true
end
you could of course change all these if .. else blocks to one liners if you prefer:
result = array.select do |item|
next if params[:user_id] && item[:user_id] != params[:user_id]
next if params[:start_date] && item[:start_date] <= params[:start_date]
next if params[:end_date] && item[:end_date] >= params[:end_date]
true
end

Related

Activeadmin custom sortable column in index

I have custom sortable column 'Status' in index, how can I make it sortable?
index do
selectable_column
column :title
column :counter
column 'Status', do |purchase|
if purchase.status == 'verified' && purchase.expiration_date < DateTime.now.utc
'ended'
elsif purchase.status == 'verified' && purchase.expiration_date >= DateTime.now.utc
'active'
else
purchase.status
end
end
end
According to the docs you should be able to pass a :sortable key to the column call like so:
index do
# SNIP
column 'Status', sortable: :status do |purchase|
# SNIP
end
end
The documentation for index table custom sorting is on the index as table page.
Solved a problem in this way
column 'Status', sortable: :status do |purchase|
if purchase.status == 'verified' && purchase.expiration_date < DateTime.now.utc
'ended'
elsif purchase.status == 'verified' && purchase.expiration_date >= DateTime.now.utc
span class: "purchase-status-active" do
'active'
end
else
purchase.status
end
end
controller do
def find_collection(options = {})
if params[:order] == 'status_desc'
super.reorder(status: :desc, expiration_date: :desc)
elsif params[:order] == 'status_asc'
super.reorder(status: :asc, expiration_date: :asc)
else
super
end
end
end

undefined local variable or method `params' for # in controller when writing multiple conditions for drop down options

I am having a view with static drop down select_tag as:
= select_tag(:option, options_for_select([['Option1', 2], ['Option2', 3], ['Option3', 4]], :selected => params[:option] ), class: 'form-control')
My controller is:
def create_report
#report = Report.create_report(params[:id], params.merge(account: current_account, user: current_user))
#report.execute
end
def execute
#items = []
if params[:option] == "Option1"
current_date = #start_date
while #end_date >= current_date
daily_items = Option1.by_account(#account).active.includes(:company, :primary_contact, :primary_addr).where('date(txn_date) = ? ', current_date)
#items << Item.new(items: daily_items, date: current_date) unless daily_items.empty?
current_date += 1.day
end
elsif params[:option] == "OPtion2"
current_date = #start_date
while #end_date >= current_date
daily_items = Option2.by_account(#account).active.includes(:company, :primary_contact, :primary_addr).where('date(txn_date) = ? ', current_date)
#items << Item.new(items: daily_items, date: current_date) unless daily_items.empty?
current_date += 1.day
end
end
end
When i am writing a condition for only one condition, it is working fine. But when I write a condition for each Options,as written in controller execute method. It is showing error as:
undefined local variable or method params for #

Search function is not working in ruby on rails

I am creating a form for my posts search. I am doing like this ....
erb form code...
<%= form_tag '/posts/search-post', :remote=> "true" do %>
<p>
<%= text_field_tag :search, params[:search], :placeholder => "Search Posts..." %><br/>
<%= radio_button_tag :day, 1, params[:day] %>None
<%= radio_button_tag :day, 2, params[:day] %>Last Week
<%= radio_button_tag :day, 3, params[:day] %>Last Month<br/>
<%= submit_tag "Search", :onclick => "document.getElementById('spinner').style.visibility='visible';document.getElementById('postlist').style.visibility='hidden'" %>
</p>
<% end %>
root.rb
match 'posts/search-post', to: 'posts#search_post'
posts_controller.rb
def search_post
if !params[:search].blank? && params[:day].blank?
#posts = Post.paginate(page: params[:page],:per_page => 5).search(params[:search])
elsif params[:search].blank? && !params[:day].blank?
#posts = Post.paginate(page: params[:page],:per_page => 5).all if params[:day] == "1"
#posts = Post.paginate(page: params[:page],:per_page => 5).where("created_at >= ?", 1.week.ago.utc) if params[:day] == "2"
#posts = Post.paginate(page: params[:page],:per_page => 5).where("created_at >= ?", 1.month.ago.utc) if params[:day] == "3"
elsif !params[:search].blank? && !params[:day].blank?
#posts = Post.paginate(page: params[:page],:per_page => 5).search(params[:search]) if params[:day] == "1"
#posts = Post.paginate(page: params[:page],:per_page => 5).search(params[:search]).where("created_at >= ?", 1.week.ago.utc) if params[:day] == "2"
#posts = Post.paginate(page: params[:page],:per_page => 5).search(params[:search]).where("created_at >= ?", 1.month.ago.utc) if params[:day] == "3"
else
end
end
Post.rb model
def self.search(search)
search_condition = "%" + search + "%"
if search
find(:all, :conditions => ['lower(content) LIKE ? OR lower(title) LIKE ?', search_condition.downcase,search_condition.downcase])
else
find(:all)
end
end
search-post.js.erb
$("#posts_list").html("<%= escape_javascript( render(:partial => "posts") ) %>");
When I search by both keyword and day type then searching is not working (Getting all post list-items). I don't know where i am wrong. Please help.
I am not sure if you've done this intentionally, but in both your elseif and else sections in your controller, you're overwriting your search results.
For example, in your else section, you first do this:
#posts = Post.paginate(page: params[:page],:per_page => 5).search(params[:search]) if params[:day] == "1"
and then you do this:
#posts = Post.paginate(page: params[:page],:per_page => 5).where("created_at >= ?", 1.week.ago.utc) if params[:day] == "2"
Which means that the second set of results that are saved in #posts will overwrite your first set of results (what was saved in #posts in your first line).
Since you're doing an "&&" operation, then you should include your result set from your first line into the second.
One solution to your problem might be to change your Post.rb model to something like this:
def self.search(search, previous_results_set)
search_condition = "%" + search + "%"
if search
if previous_result_set.nil?
find(:all, :conditions => ['lower(content) LIKE ? OR lower(title) LIKE ?', search_condition.downcase,search_condition.downcase])
else
previous_result_set.find(:all, :conditions => ['lower(content) LIKE ? OR lower(title) LIKE ?', search_condition.downcase,search_condition.downcase])
else
find(:all)
end
end
My code might not be perfect and you can probably find a more efficient way of doing it in your code, but you get the idea. Even when you user the .where, you need to perform the .where on the previous result set, not on the Post model as a whole again. That way you will be filtering your previously filtered results.
Hope this helps.

Validate params from request and join result request for Thinking Sphinx search filter

Im newbie on ruby on rails)
Ok, I have controller with index action:
def index
condition = ['fulltime','parttime','remote','forone']. select{ |t| params.has_key?(t.to_sym) }.join(' | ')
Advert.search params[:search],:order => :created_at, :sort_mode => :desc, :conditions => {:employment_type=>condition}
But it peace of code:
['fulltime','parttime','remote','forone']. select{ |t| params.has_key?(t.to_sym) }
return nil
Why?:))
I don't want to write code with a bunch of checks like:
if !fulltime.nil? && !fulltime.blank?
condition = "fulltime"
end
if !parttime.nil? && !parttime.blank?
if !condition.nil? && !condition.blank?
condition = condition + " | parttime"
else
condition ="parttime"
end
end
But my way with array.select method is not working:(
Could you give me some advices?) Thanks!
I tried your code on irb as follows:
> params = { :fulltime => "1" }
=> {:fulltime=>"1"}
> ['fulltime','parttime','remote','forone']. select{ |t| params.has_key?(t.to_sym) }.join(' | ')
=> "fulltime"
So it is working fine. If you are getting nil from that code, then the params are being set to nil, or the params don't have any of ['fulltime','parttime','remote','forone'] as keys.
Check out Rails params explained? thread; likely to give an idea as to how to set the params correctly.

Please explain this snippet of haml code/documentation

%div{:class => [#item.type, #item == #sortcol && [:sort, #sortdir]] } Contents
could render as any of:
<div class="numeric sort ascending">Contents</div>
<div class="numeric">Contents</div>
<div class="sort descending">Contents</div>
<div>Contents</div>
I don't really understand the #sortcol && [:sort, #sortdir] part of this snippet.
This relies on operator precedence. So it is evaluated like this:
#item == #sortcol is either true or false.
when false
&& returns false because the other part is not evaluated
hence the code reduces to :class => [#item.type]
when true
&& returns the second part of the expression. In this case the array [:sort, #sortdir]
HAML automatically flattens the array before rendering thus it's equivalent to :class => [#item.type, :sort, #sortdir]
[#item.type, #item == #sortcol && [:sort, #sortdir]]
=>
# if #item.type is blank, so class is still empty
# if #item.type is "numeric" class is "numeric"
class = #item.type
# if #item equal #sortcol
# class will append "sort" and #sortdir if it is not empty.
if #item == #sortcol
class += "sort"
class += #sortdir
end
This construction #item == #sortcol && [:sort, #sortdir] will return [:sort, #sortdir] only if #item == #sortcol is true

Resources