I'm querying orders by date range.
It is working now but I have the logic in the controller not in the model. I know that this should be in the model instead.
I've tried several approaches but I've had no luck.
Question:
What is the proper way of doing this?
I'm looking at the Rails Guides Active Record Querying section 2.2 Array Conditions:
http://guides.rubyonrails.org/active_record_querying.html
Also researched several question here in Stack overflow:
undefined local variable or method `params' for #<Result:0x3904b18>
undefined local variable or method `user_params' rails 4
ruby query between two date parameters
orders.rb Empty now to avoid errors
def self.search_range
end
orders_controller.rb
def search_range
#orders = Order.where("created_at >= :start_date AND created_at <= :end_date",{start_date: params[:start_date], end_date: params[:end_date]}).order("created_at desc")
end
search_range.html.erb Here I'm entering the date range
<div class="container-fluid events-container">
<div class="row">
<div class="col-sm-12">
<h1>Orders</h1>
</div>
</div>
<div class="row">
<div class="col-sm-6 form-group">
<%= form_tag search_range_path, :method => 'get', class:"" do %>
<p>
<%= text_field_tag :start_date, params[:start_date] %>
<%= text_field_tag :end_date, params[:end_date] %>
<%= submit_tag "Search", :name => nil, class:"btn btn-primary" %>
</p>
<% end %>
</div>
</div>
<table class="table">
<tr>
<th>amount</th>
<th>status</th>
<th>Last Updated</th>
<th>Order Id</th>
<th>manage</th>
</tr>
<% #orders.each do |order| %>
<tr>
<td><%= order.total %></td>
<td><%= order.order_status.name %></td>
<td><%= order.created_at.strftime("%m/%d/%Y") %></td>
<td><%= order.id %></td>
<td><%= link_to 'details', order %> |
<%= link_to 'edit', edit_order_path(order) %> |
<%= link_to 'delete', order_path(order), method: :delete, data: { confirm: 'Are you sure?' } %>
</td>
</tr>
<% end %>
<tr><td colspan="4"></td></tr>
</table>
<div class="row">
<div class="col-sm-12">
<hr>
</div>
</div>
</div>
I took the liberty to also eager load the association, order_status, because in your view it looks like you are referencing that table. Here is a solid guide on eager loading.
Below should get you to your solution. Good for you for writing the correct query in your controller, and recognizing the need to refactor to your model. The below is also not tested, so let me know if it doesn't produce the results you need. The code below can also lead to errors, if the params are not valid dates, so you may want to go further to ensure it correctly handles errors.
# controller
#orders = Order.includes(:order_status).
filter_between_dates(params[:start_date], params[:end_date]).
recent
# model
scope :filter_between_dates, (lambda do |start_date, end_date|
return all unless start_date.present? && end_date.present?
where('created_at >= ? AND created_at <= ?', start_date, end_date)
end)
# Order based on created_at date.
#
# examples:
# Order.recent
# Order.recent('asc')
scope :recent, -> (default = 'desc') { order(created_at: default.to_sym) }
You could even go one step further and refactor this using the query object pattern.
# app/finders/orders/search_finder.rb
module Orders
class SearchFinder
attr_reader :params
def initialize(params)
#params = params
end
def execute
Order.includes(:order_status).
filter_between_dates(params[:start_date], params[:end_date]).
recent
end
end
end
# controller
#orders = Orders::SearchFinder.new(params).execute
Related
My application needs to duplicate a Skill (from skills index) as many times the user needs it in his cart. So I decided to trigger the add-to-cart method of the skills_controller when the related form, including the number of duplicates and the Skill's id, is submitted. For this purpose, I added counter to the strong parameters of skills_controller.
Unfortunately, I am missing something to correctly setup the form: when submitted, it triggers the create method. Here is the code:
routes.rb extract
resources :skills, :path => "variables" do
resources :values_lists
member do
post :add_to_cart
get :create_values_list
get :upload_values_list
get :remove_values_list
end
collection do
get :index_all
end
end
skills_controller.rb method
def add_to_cart
#template_skill = Skill.find(params[:id])
iterations = params[:skill][:counter].to_i
until iterations == 0
#skill = #template_skill.deep_clone include: [:translations, :values_lists]
#skill.business_object_id = session[:cart_id]
#skill.template_skill_id = #template_skill.id
#skill.code = "#{#template_skill.code}-#{Time.now.strftime("%Y%m%d:%H%M%S")}-#{iterations}"
#skill.is_template = false
#skill.save
iterations -= 1
end
#business_object = BusinessObject.find(session[:cart_id])
redirect_to #business_object, notice: t('SkillAdded2BO') # 'Skill successfully added to business object'
end
index.html.erb table content
<tbody>
<% #skills.each do |skill| %>
<tr data-href="<%= url_for skill %>">
<% if not session[:cart_id].nil? %>
<td>
<%= form_with model: #skill, :action => "add_to_cart", :method => :post, remote: false do |f| %>
<%= f.text_field :counter, value: "1", class: "mat-input-element", autofocus: true %>
<button type="submit" class="mat-icon-button mat-button-base mat-primary add-button" title="<%= t('AddToUsed') %>">
<span class="fa fa-plus"></span>
</button>
<% end %>
</td>
<% end %>
<td class="no-wrap"><%= skill.code %></td>
<td><%= link_to skill.translated_name, skill %></td>
<td><%= link_to translation_for(skill.parent.name_translations), skill.parent %></td>
<td><%= skill.responsible.name %></td>
<td><%= skill.updated_by %></td>
<td class="text-right"><%= format_date(skill.updated_at) %></td>
</tr>
<% end %>
</tbody>
Thanks a lot for your help!
According to this form helpers guide, the syntax you used doesn't exist
form_with model: #model, action: :custom_action
So in this case, you have to specify the url parameter for form_with to make it works.
<%= form_with model: #skill, url: :add_to_cart_skill_path(#skill), method: :post, remote: false do |f| %>
I have manager remark model that takes input as a remark and decision value and saves it with the project site ID. I have a project site model that takes input as name, date, and file and stores it. Many remarks have a many to one relation with project site ID, and the project site belongs to the manager remark. I want to access the decision attribute boolean value in project site index form, but I am unable to access that boolean value in the index page of the project site. Here is my code of project site and manager remarks model, view and controller-
project site index.html.erb
<table>
<thead>
<tr>
<th>Name</th>
<th>Date</th>
<th>Attendance</th>
<th>Status</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #project_sites.each do |project_site| %>
<tr>
<td><%= project_site.name.titleize %></td>
<td><%= project_site.date %></td>
<td><%= link_to ' View attendance', project_site.file, :class => "fi-page-export-csv" %></td>
<td><%= "here i want to access manager remark decision value" %></td>
<td><%= link_to 'Remark ', project_site %><span>(<%= project_site.manager_remarks.size %>)</span></td>
<td><%= link_to 'Edit', edit_project_site_path(project_site) %></td>
<td><%= link_to 'Destroy', project_site, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
project site controller
def index
#project_sites = ProjectSite.all.order("created_at DESC")
#manager_remark = ManagerRemark.joins(:project_site).where(:project_sites => { :user_id => #user.id })
end
# GET /project_sites/1
# GET /project_sites/1.json
def show
#manager_remark = ManagerRemark.new
#manager_remark.project_site_id = #project_site.id
end
# GET /project_sites/new
def new
#project_site = ProjectSite.new
end
def project_site_params
params.require(:project_site).permit(:name, :date, :file)
end
manager_remark controller
class ManagerRemarksController < ApplicationController
def create
#manager_remark = ManagerRemark.new(remark_params)
#manager_remark.project_site_id = params[:project_site_id]
#manager_remark.save
redirect_to project_site_path(#manager_remark.project_site)
end
def remark_params
params.require(:manager_remark).permit(:remark, :decision)
end
end
manager_remark view form
<%= form_for [ #project_site, #manager_remark ] do |f| %>
<div class="row">
<div class="medium-6 columns">
<%= f.radio_button :decision, true %>
<%= f.label :approve %>
<%= f.radio_button :decision, false %>
<%= f.label :reject %>
</div>
<br>
<br>
<div class="medium-6 cloumns">
<%= f.label :remark %><br/>
<%= f.text_area :remark %>
</div>
</div>
<div>
<%= f.submit 'Submit', :class => 'button primary' %>
</div>
<% end %>
routes.rb
Rails.application.routes.draw do
root to: 'home#index'
devise_for :users
resources :project_sites do
resources :manager_remarks
end
get '/project_manager_level_two' => 'project_manager_level_two#index'
get '/project_managers' => 'project_managers#index'
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
If I understand correctly, you have a ProjectSite that contains a ManagerRemark with a decision, right? If that's the case, the simple answer is:
<%= project_site.ManagerRemark.decision %>
If you are saying that each ProjectSite has many ManagerRemarks, you'll want to place the above inside a loop, like so:
<% project_site.manager_remarks.each do |manager_remark| %>
<%= manager_remark.decision %><br/>
<% end %>
This assumes that your models are correctly configured to recognize these relationships. The above may also be optimized by adding an include clause to your fetch inside the controller and there's no need to fetch the ManagerRemark objects separately. Therefore, you'd probably want something like:
def index
#project_sites = ProjectSite.all.includes( :manager_remark ).order("created_at DESC")
end
I would like to be able to search orders by id or by order status.
My current code is working but not 100%.
There is a has_many relationship between the Order and the Order Status models.
The order status model has four entries:
1.Processing , 2.Completed, 3.Cancelled, 4.Refunded
Example:
I have a simple form to enter the order id and another form with a select tag
with all the Order Statuses to search by order status.
If I search for order id 1, I get all the orders with a number 1 in the id and I also get all the orders with order status 1.
I would like get a result of either order id or order status.
Order model
class Order < ActiveRecord::Base
belongs_to :order_status
def self.search(search)
where("cast(id as text) LIKE ? OR order_status_id LIKE ? ", "%#{search}%", "%#{search}%")
end
end
Order Status model
class OrderStatus < ActiveRecord::Base
has_many :orders
end
Orders Controller
def index
#order_statuses = OrderStatus.all
if params[:search]
#orders = Order.search(params[:search])
else
#orders = Order.all
end
end
Order index view
<div class="row">
<div class="col-sm-6 form-group">
<%= form_tag orders_path, :method => 'get', class:"" do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil, class:"btn btn-primary" %>
</p>
<% end %>
</div>
<div class="col-sm-6 form-group">
<%= form_tag orders_path, :method => 'get', class:"" do %>
<p>
<%= select_tag :search, options_from_collection_for_select(OrderStatus.all, :id, :name, params[:search]) %>
<%= submit_tag "Search", :name => nil, class:"btn btn-primary" %>
</p>
<% end %>
</div>
</div>
<table class="table">
<tr>
<th>Order Id</th>
<th>amount</th>
<th>status</th>
<th>Last Updated</th>
<th>manage</th>
</tr>
<% #orders.each do |order| %>
<tr>
<td><%= order.id %></td>
<td><%= order.total %></td>
<td><%= order.order_status.name %></td>
<td><%= order.updated_at %></td>
<td><%= link_to 'details', order %> |
<%= link_to 'edit', edit_order_path(order) %> |
<%= link_to 'delete', order_path(order), method: :delete, data: { confirm: 'Are you sure?' } %>
</td>
</tr>
<% end %>
<tr><td colspan="4"></td></tr>
</table>
I've researched the following links but I'm not finding or understanding a solution.
Links:
http://railscasts.com/episodes/37-simple-search-form?autoplay=true
http://railscasts.com/episodes/111-advanced-search-form-revised?autoplay=true
http://guides.rubyonrails.org/active_record_querying.html
Rails Search Form
Build static dropdown menu for simple search Rails 3
You can do a search by either order_id or order_status :name attribute with the following
class Order < ActiveRecord::Base
belongs_to :order_status
def self.search(query)
query.to_s.is_i? ? where(id: query) : joins(:order_status).where('order_statuses.name LIKE ?', "%#{query}%")
end
end
In order to use the is_i? method you will need to extend the String class by creating an initializer file to require a new String extension file
# config/initializers/core_extensions.rb
Dir[File.join(Rails.root, "lib", "core_extensions", "*.rb")].each {|f| require f }
and then create your new String extension file and is_i? method
# lib/core_extensions/string.rb
class String
def is_i?
/\A[-+]?\d+\z/ === self
end
end
credit this SO answer for the is_i? method
There's no need to cast the id into text and then using like to match it. This should be enough to get what you need.
class Order < ActiveRecord::Base
belongs_to :order_status
def self.search(search)
where("id = ? OR order_status_id LIKE ? ", search, "%#{search}%")
end
end
I have a model called Listing that I use to represent a listing for a sublet. I created a model called Filter that I use to filter the sublets based on a form that the user fills out. Upon filling out the form, I want the user to be redirected to a template that has all of the listings that were returned from the filter.
Here is my Filter model.
class Filter < ActiveRecord::Base
attr_accessible :air_conditioning, :available_rooms, :bathrooms, :furnished, :negotiable, :new, :parking, :maximum_price, :private_bathroom, :show, :term, :total_rooms, :utilities, :washer_dryer
serialize :term
def listings
#listings ||=find_listings
end
private
def find_listings
listings=Listing.order(:price)
listings=Listing.where("listings.price <= ?", maximum_price) if maximum_price.present?
listings=Listing.where(total_rooms: total_rooms) if total_rooms.present?
listings=Listing.where(available_rooms: available_rooms) if available_rooms.present?
listings=Listing.where(bathrooms: bathrooms) if bathrooms.present?
listings=Listing.where(term: term)
listings=Listing.where(furnished: furnished)
listings=Listing.where(negotiable: negotiable)
listings=Listing.where(utilities: utilities)
listings=Listing.where(air_conditioning: air_conditioning)
listings=Listing.where(parking: parking)
listings=Listing.where(washer_dryer: washer_dryer)
listings=Listing.where(private_bathroom: private_bathroom)
listings
end
end
Here is the show method for filter.
<p id="notice"><%= notice %></p>
<%= render (#filter.listings) %>
Pretty simple.
And here is the template called _listing.html.erb
<div style="padding:5px">
<%= link_to 'New Listing', new_listing_path,{:style=>'', :class => "btn"} %>
<h1>Available Sublets</h1>
<table id="listingTable" class="table table-bordered table-hover">
<tr>
<th><%= link_to 'Filter', new_filter_path,{:style=>'', :class => "btn"} %><%= link_to 'Clear Filter', listings_path, {:style=>'', :class => "btn"} %></th>
<th>Address</th>
<th><u><%= "Price Per Month" %></u></th>
<th>Description</th>
</tr>
<% if #listings !=nil %>
<% #listings.each do |listing| %>
<tr onmouseover="this.style.cursor='pointer';"
onclick="window.location.href = '<%= url_for(:controller => 'listings', :action => 'show', :id=>listing.id) %>' " >
<td><%= image_tag listing.photo.url(:small) %></td>
<td><%= listing.address %></td>
<td>$<%= listing.price %></td>
<td width="40%"><%= listing.description %></td>
</tr>
<% end %>
<% end %>
<% else if #listings==nil %>
<p> Sorry, No Sublets Fit Your Criteria! </p>
<% end %>
</table>
However, the filter never returns any results... I have tested atleast 20 times with queries that should definitely return atleast 1 listing. I feel like I have a naming convention problem but I have never used partials before. any help would be great.
This code:
listings=Listing.where(term: term)
listings=Listing.where(furnished: furnished)
listings=Listing.where(negotiable: negotiable)
listings=Listing.where(utilities: utilities)
listings=Listing.where(air_conditioning: air_conditioning)
listings=Listing.where(parking: parking)
listings=Listing.where(washer_dryer: washer_dryer)
listings=Listing.where(private_bathroom: private_bathroom)
Is not actually filtering listings down further. Basically, it's reassigning listings again and again and again.
If you want to apply successive filters to listings, do this:
listings = Listing.where(term: term)
listings = listings.where(furnished: furnished)
listings = listings.where(negotiable: negotiable)
...
I am working on my first web and Rails app and can not figure out how to get a search feature work from my main page to one of the controllers.
How to send the request and redirect to a results page to show the results from the search.
I can't get this to work as am not sure how to route in a way my variable #histories will keep results and display on the show page.
I would appreciate some insight into search from any page and displaying results on a dedicated page.
Here is what i have so far in terms of the controller, model and partials.
Shipments Model:
def self.search(search)
search_condition = search
find_by_sql("SELECT cargo_transit_histories.current_location,cargo_transit_histories.updated_at FROM cargo_transit_histories
INNER JOIN shipments ON shipments.id = cargo_transit_histories.shipment_id WHERE shipments.tracking_number='search_condition'")
end
Tracking Controller:
def search
#histories = Shipment.search(params[:search])
render('show')
end
Show (Found in Tracking view):
<div class="search_result">
<%= render 'track/search_results' %>
</div>
_search (partial):
<%= form_tag :controller => 'tracking', :action => 'search', :method => 'get' do %>
<%= text_field_tag :search, params[:search], :id => 'search_field' %>
<%= submit_tag "Search", :name => nil %>
<%= link_to_function "Clear", "$('search_field').clear()" %>
<% end %>
_search_results (partial):
<div class="Results list">
<table class="Resultslisting" summary="Result list">
<tr class="header">
<th>Current Location</th>
<th>Date/Time</th>
</tr>
<% if !#histories.empty? %>
<% #histories.each do |result| %>
<tr>
<td><%= result.current_location %></td>
<td><%= result.updated_at %></td>
</tr>
<% end %>
</table>
<% else %>
<p> The tracking number does not exist!</p>
<% end %>
</div>
Try something like the following adapted example:
https://gist.github.com/4173716
But you need to dig a bit deeper into Rails 3 to understand why.