Rails controller index exclude records - ruby-on-rails

I have the following index in workorder controller:
def index
#workorders = Workorder.scoped
#workorders = Workorder.where("created_at > #{params[:after]}") if params[:after].present?
end
How would I add the following so that it becomes an AND. I want it to only include a workorder if maxsync <> 'E'. Even if the parameter :after is present or not.
I tried this:
#workorders = Workorder.scoped.where("maxsynch != 'E' ")
Thanks for the help!

You can chain scopes like this:
def index
#workorders = Workorder.scoped.where("maxsynch != 'E' ")
#workorders = #workorders.where("created_at > ?", params[:after]) if params[:after].present?
#examples:
#workorders = #workorders.where(parent_id: params[:parent_id]) if params[:parent_id].present?
#workorders = #workorders.active if params[:filter_active].present?
end

Related

Rails Ransack - removing element from array

I'm learning how to use ransack, so I have a problem there I'm not sure if it is because the ransack or if it is because the array.
I have a form with 2 text fields (:search and :discipline). So I'm trying do a search using the 1º field parameter AND the 2º field parameter.
The idea is search for all elements that comes from the 1º parameter (field :search, and then remove all the elements that are different from the 2º parameter (field :discipline).
class PagesController < ApplicationController
def home
#rooms = Room.limit(6)
end
def search
if params[:search].present? && params[:search].strip != ""
session[:loc_search] = params[:search]
end
if params[:discipline].present? && params[:discipline].strip != ""
session[:loc_discipline] = params[:discipline]
end
arrResult = Array.new
if session[:loc_search] && session[:loc_search] != ""
#rooms_address = Room.where(active: true).near(session[:loc_search], 5, order: 'distance')
else
#rooms_address = Room.where(active: true).all
end
#search = #rooms_address.ransack(params[:q])
#rooms = #search.result
#arrRooms = #rooms.to_a
if (session[:loc_discipline] && !session[:loc_discipline].empty?)
#rooms.each do |room|
not_available = Room.where(
"(room_type != ?)",
session[:loc_discipline]
)
if not_available.length > 0
#arrRooms.delete(room)
end
end
end
end
end
My #arrRooms is returning NULL after I try do this #arrRooms.delete(room).
I dont know if have a better way to do this, but I'm trying do it like a tutorial that I found.
I assume that you're trying to show all rooms that are not available?
I think the best strategy is to load what you really want, and not loading everything an then deleting the things you don't need. Your code is really hard to read, I suggest you take a little tutorial like this: http://tryruby.org/levels/1/challenges/0, or this: https://www.codeschool.com/courses/ruby-bits
Try extracting code like where(active: true) into a scope like:
class Room < ActiveRecord::Base
scope :active, -> { where(active: true) }
scope :available, -> (discipline) { where.not(room_type: discipline) }
end
In your controller you can then make this:
def index
#rooms = Room.active.available(params[:discipline])
search_param = params[:search].present?
if search_param.present?
#rooms = #rooms.near(session[:loc_search], 5, order: 'distance')
end
#rooms = #rooms.ransack(params[:q]).result(distinct: true)
end
This is what I could guess out of your code.

How to merge two objects in Ruby on Rails

I'm trying to retrieve from the database two contents: the first one with the field source equal to "imported" (which means that we import it from the excel spreadsheet), and the second one with source != imported (we create it from scratch). Attached is my code:
def index
add_breadcrumb 'Projects', projects_path
add_breadcrumb #project.name, #project
add_breadcrumb "List #{#category.display_name} Content", project_category_contents_path(#project, #category)
#contents_imported = Content.of_project(#project).with_category(#category).imported.order('contents.created_at asc')
#contents_not_imported = Content.of_project(#project).with_category(#category).not_imported.order('contents.created_at desc')
#page = params[:page]
#contents = #contents_not_imported << #contents_imported
#q = #contents.search(params[:q])
#content = #q.result(distinct: true).page(#page).per(20)
end
#contents_imported = Content.of_project(#project).with_category(#category).imported.order('contents.created_at asc')
#contents_not_imported = Content.of_project(#project).with_category(#category).not_imported.order('contents.created_at desc')
And I want to combine the two results before showing it:
#contents = #contents_not_imported << #contents_imported
but it didn't work. How can I do that?
If both of them are arrays and are having same type of objects you can do Result = Arr1 | Arr1
That also removes the duplicates. Its like boolean UNION. In your case #contents = #contents_not_imported | #contents_imported
The problem is that you want to concatenate results, but you also want to continue treating the combined results as an ActiveRelation (call .search on it). Here's a simpler approach that avoids the need for concatenation in the first place. You will need a more complex ORDER BY clause to accomplish this, however:
#page = params[:page]
#contents = Content.of_project(#project).with_category(#category).
order('CASE WHEN source <> "imported" THEN contents.created_at END desc, CASE WHEN source = "imported" THEN contents.created_at END asc')
#q = #contents.search(params[:q])
Concatenating the arrays is done with the plus sign
You are getting undefined method search for Array because, concatenating will return you an array. And you can't call search method on that Array
EDIT
def index
add_breadcrumb 'Projects', projects_path
add_breadcrumb #project.name, #project
add_breadcrumb "List #{#category.display_name} Content", project_category_contents_path(#project, #category)
contents_imported_ids = Content.of_project(#project).with_category(#category).imported.order('contents.created_at asc').map(&:id)
contents_not_imported_ids = Content.of_project(#project).with_category(#category).not_imported.order('contents.created_at desc').map(&:id)
#page = params[:page]
contents_ids = contents_imported_ids + contents_not_imported_ids
contents = Content.where(content_ids)
#contents = content_ids.collect{|id| contents.detect{|c| c.id == id}}
#q = #contents.search(params[:q])
#content = #q.result(distinct: true).page(#page).per(20)
end
Just create a new Relation with the conditions of imported or not imported, after that, order all the records (if order is important to #contents and #content):
def index
add_breadcrumb 'Projects', projects_path
add_breadcrumb #project.name, #project
add_breadcrumb "List #{#category.display_name} Content", project_category_contents_path(#project, #category)
#contents_imported = Content.of_project(#project).with_category(#category).imported.order('contents.created_at asc')
#contents_not_imported = Content.of_project(#project).with_category(#category).not_imported.order('contents.created_at desc')
#page = params[:page]
imported = #contents_imported.where_values.reduce(:and)
not_imported = #contents_not_imported.where_values.reduce(:and)
#contents = Content.where(imported.or(not_ipmorted)).order('CASE contents.imported WHEN true THEN contents.created_at asc ELSE contents.created_at desc END')
#q = #contents.search(params[:q])
#content = #q.result(distinct: true).page(#page).per(20)
end
Now you can call Ransack#search on #contents because it is an ActiveRecord::Relation. I assume that the imported scope take a field contents.imported with value true.
If I wrote this without errors, this must works.

Rails4 error wrong number of arguments (1 for 0)

I am getting this error When I put the condition in rails query.
def index
#patients = current_hospitaladmin.patients.all(:conditions => "discharge_status = 0")
respond_with(#patients)
end
You can simple try this
def index
#patients = current_hospitaladmin.patients.where(discharge_status: 0)
respond_with(#patients)
end

How to handle multiple conditions of instance variable assignment

I have the following in my controller that will assign a different collection of results depending on what params are received with an Ajax call. It is messy and i would like to just call a function with all the logic in rather than all this in my index controller
class PublicController < ApplicationController
def index
if params[:literacy_param].present?
#skills = Skill.search(params)
elsif params[:numeracy_param].present?
#skills = Skill.numeracy_default_params
elsif params[:numeracy_number_skills].present?
#skills = Skill.numeracy_number_skills
elsif params[:numeracy_measuring_skills].present?
#skills = Skill.numeracy_measuring_skills
elsif params[:numeracy_data_skills].present?
#skills = Skill.numeracy_data_skills
else
#skills = Skill.default_params
end
end
end
Im just a bit unsure on how to set out my function so that it can read the params that are being sent,
I have come up with this so far
private
def skills(params)
if params[:literacy_param].present?
#skills = Skill.search(params)
elsif params[:numeracy_param].present?
#skills = Skill.numeracy_default_params
elsif params[:numeracy_number_skills].present?
#skills = Skill.numeracy_number_skills
elsif params[:numeracy_measuring_skills].present?
#skills = Skill.numeracy_measuring_skills
elsif params[:numeracy_data_skills].present?
#skills = Skill.numeracy_data_skills
else
#skills = Skill.default_params
end
end
Then in my index action i would do
#skills = skills(params)
would this be an efficient way?
Thanks
You can do this
class PublicController < ApplicationController
def index
skills = ['literacy_param', 'numeracy_param', 'numeracy_number_skills', 'numeracy_measuring_skills', 'numeracy_data_skills']
common_in_params = (skills & params).first
#skills = common_in_params.present? ? (common_in_params.eql?('literacy_param') ? Skill.search(params) : Skill.send(common_in_params)) : Skill.default_params
end
end
You can define skills array in an initializer for resusability
One way of doing it would be this:
def skills(params)
set_of_skills = params.slice(
:numeracy_param,
:numeracy_number_skills,
:numeracy_measuring_skills,
:numeracy_data_skills,
).first
#skills = if params[:literacy_param]
Skill.search(params)
elsif set_of_skills
Skill.public_send(set_of_skills)
else
Skill.default_params
end
end
I would also advise to have this extracted into a lib/ folder, and unit-tested. So that in your controller you could perform the following:
def index
#skills = SkillSearch.new(params).search
end
Two ways I can think of doing this right now:
Wrap the params in a unique key. As in params = { :keyword => :literacy_param }, and then use this unique key to identify the right operation.
In you skill.rb:
def self.filter(params)
if params[:keyword] == :literacy_param
search(params)
elsif available_filters.include?(params[:keyword])
public_send(params[:keyword])
else
default_params
end
end
private
def self.available_filters
%i{numeracy_default_params numeracy_number_skills numeracy_measuring_skills numeracy_data_skills}
end
considering that instead of :numeracy_param, you send :numeracy_default_params in :keyword key. Otherwise you'll have to make another elsif inside filter method.
then in your index method:
def index
#skilles = Skill.filter(params)
end
You create a separate filter class, which is an expandable solution, just in case when you need to go for complex search queries and filtering.
Let's call it SkillSeacrher, inside you app/models/skill_searcher.rb:
class SkillSearcher
attr_reader :keyword
def initialize(keyword)
#keyword = keyword
end
def filter
if keyword == :literacy_param
Skill.search(params)
elsif available_filters.include?(keyword)
Skill.public_send(keyword)
else
Skill.default_params
end
end
private
def self.available_filters
%i{numeracy_default_params numeracy_number_skills numeracy_measuring_skills numeracy_data_skills}
end
end
then in index method:
def index
#skills = SkillSearcher.new(params[:keyword]).filter
end
However, you can do one more change to filter method(depends on your taste):
def filter
if keyword == :literacy_param
Skill.search(params)
else
Skill.public_send(available_filters.include?(keyword) ? keyword : :default_params)
end
end
And, if you have all these methods accepting params as arguments then it'd be much more sleek:
def filter
Skill.public_send(available_filters.include?(keyword) ? keyword : :default_params, params)
end

Rails - Fetch results on the basis of number of params in query string

I am working on an events application where i want to filter events depending on the 3 parameters location or starts_at or ends_at in the query string. There can be any one, two or all the parameters in the query string. In i use if-else statement i need to make 6 cases which will make my code clumsy. Rather i am thinking to implement something this way:
class EventsController < ApplicationController
def index
unless params.empty?
unless params[:location].nil?
#events = Event.where("location = ?", params[:location])
end
unless params[:starts_at].nil?
unless #events.empty?
#events = #events.where("start_date = ?", params[:start_date])
else
#events = Event.where("Date(starts_at) = Date(?)", params[:starts_at])
end
end
unless params[:ends_at].nil?
unless #events.empty?
#events = #events.where("end_date = ?", params[:end_date])
else
#events = Event.where("Date(ends_at) = Date(?)", params[:ends_at])
end
end
end
end
end
But this code doesnt work since where query doen not work on an array. Can someone suggest me some solution for this..
You should be able to pass your params hash directly to where, and it will form the correct SQL based on the keys and values of that hash:
Event.where(params)
An example in the console:
1.9.3p194 :001 > puts Example.where(:location => 'here', :started_at => '2012-08-13').to_sql
SELECT "examples".* FROM "examples" WHERE "examples"."location" = 'here' AND "examples"."started_at" = '2012-08-13'
Try Following
def index
unless params.empty?
where_array, arr = [], []
if params[:location]
where_array << "location = ?"
arr << params[:location]
end
if params[:starts_at]
where_array << "start_date = ?"
arr << params[:starts_at]
end
if params[:ends_at]
where_array << "end_date = ?"
arr << params[:ends_at]
end
#events = arr.blank? ? [] : Event.where([where_array.join(" AND "), *arr])
end
end

Resources