Here is the table:
|policies|
|id| |name| |date|
1 ABC 2013-01-01
2 DEF 2013-01-21
Here is the controller:
class PolicyController < ApplicationController
def index
#policies = Policy.find(:all,:conditions=>['date BETWEEN ? AND ?',params[cam],params[:cam2] ])
end
end
Here is the model:
class Policy < ActiveRecord::Base
end
Here is the view:
<% CalendarDateSelect.format=(:hyphen_ampm )%>
<% calendar_date_select_style "silver" %>
<% translation_calendar %>
<% form_tag :controller=>"policy",:action=>"index" do %>
From: <%= calendar_date_select_tag "cam", params[:cam] %>
To: <%= calendar_date_select_tag "cam2",params[:cam2] %>
<%= submit_tag "Search", :name => nil %></p>
<% end %>
<% #policies.each |p| do %>
<%= p.date %>
<% end %>
How can block the SEARCH button until my 2 calendar text have values?
I tried this:
class Policy < ActiveRecord::Base
validates_presence_of :cam
end
Please somebody can help me please or maybe a javascript?
I will appreciate all kind of help.
Here is what friends told me:
named_scope :by_calendar_date,lambda { |cam1, cam2| } {
if cam1.nil? && cam2.nil?
scoped
elsif cam1.nil?
where("date < ?",cam2)
elsif cam2.nil?
where("date > ?", cam1)
else
where("date BETWEEN ? AND ?",cam1,cam2)
end
}
#this would perform the same functionality so both are not needed but just for edification
def self.by_calendar_date(cam1,cam2)
if cam1.nil? && cam2.nil?
scoped
elsif cam1.nil?
where("date < ?",cam2)
elsif cam2.nil?
where("date > ?", cam1)
else
where("date BETWEEN ? AND ?",cam1,cam2)
end
end
Since this is a search feature you do not need to validate in my opinion you could just do this
class Policy < ActiveRecord::Base
named_scope :by_calendar_date,lambda{|cam1,cam2|
if cam1.nil? && cam2.nil?
{:conditions => {}}
elsif cam1.nil?
{:conditions => ["date < ?",cam2]}
elsif cam2.nil?
{:conditions => ["date > ?", cam1]}
else
{:conditions => ["date >= ? AND date <= ?",cam1,cam2]}
end
}
end
call with
def index
#policies = Policy.by_calendar_date(params[:cam1],params[:cam2])
end
This way the user can set either param individually or none at all
Check out this fiddle... http://jsfiddle.net/qKG5F/641/
HTML
// note the change... I set the disabled property right away
<input type="submit" id="register" value="Register" disabled="disabled" />
JavaScript
(function() {
$('form > input').keyup(function() {
var empty = false;
$('form > input').each(function() {
if ($(this).val() == '') {
empty = true;
}
});
if (empty) {
$('#register').attr('disabled', 'disabled'); // updated according to http://stackoverflow.com/questions/7637790/how-to-remove-disabled-attribute-with-jquery-ie
} else {
$('#register').removeAttr('disabled'); // updated according to http://stackoverflow.com/questions/7637790/how-to-remove-disabled-attribute-with-jquery-ie
}
});
})()
The nice thing about this is that it doesn't matter how many input fields you have in your form, it will always keep the button disabled if there is at least 1 that is empty. It also checks emptiness on the .keyup() which I think makes it more convenient for usability.
I hope this helps.
Related
I do have a more elaborate index method in my events controller
def index
if params[:q]
params[:q][:combinator] = "and"
params[:q][:groupings] = []
split_geo = params[:q][:address_or_city_or_state_or_country_or_continent_cont_all].split((/(,\s*)+/))
split_geo.map! do |a|
I18n.transliterate a
end
split_geo.each_with_index do |word, index|
params[:q][:groupings][index] = { address_or_city_or_state_or_country_or_continent_cont_all: word }
end
end
#q = Event.ransack(params[:q])
#pagy, #events = pagy(#q.result(distinct: true))
end
In my events index page I have:
<h2>Upcoming Events</h2>
<br>
<%== pagy_bootstrap_nav(#pagy) %>
<br>
<div class="event-list-wrapper">
<% #events.upcoming_events.each do |event| %>
<%= render 'event', event: event %>
<% end %>
</div>
When I remove my upcoming_events scope, the records will display correctly.
In my event.rb model I have:
scope :upcoming_events, -> { where('event_start_date > ?', Time.now).or(where('event_end_date > ?', Date.yesterday)) }
Am I missing something in order to get pagy with work with my event scope?
I have a rails app in which i have products and their variants.
product.rb
class Product < ActiveRecord::Base
has_many :variants
scope :with_min_range, lambda { |min|
where(" (variant_price) >= ?", "#{min.to_i}")
}
scope :with_max_range, lambda { |max|
where("(variant_price) <= ?", ["#{max.to_i}"])
}
def price_range
return #price_range if #price_range
return #price_range = ['N/A', 'N/A'] if active_variants.empty?
#price_range = active_variants.minmax {|a,b| a.price <=> b.price }.map(&:price)
end
def price_range?
!(price_range.first == price_range.last)
end
end
the way i fetch the price range of the product is
index.html.erb
<% #products.each do |product| %>
<figcaption>
<h4 class="aa-product-title"><%= link_to product.name, product_path(product) %></h4>
<span class="aa-product-price"><%= number_to_currency(product.price_range.first, :locale => :in ) %>
<% if product.price_range? %>
to
<%= number_to_currency(product.price_range.last, :locale => :in) %>
<% end %></span>
</figcaption>
<% end %>
Now you can see in the product.rb i want to fetch the product based on the price so that in the with_min_range the result will be the products whose variants' minimum price range will be greater than the value of min
and in the with_max_range the result will be the products whose variants' maximum price would be less than the max
P.S - I have given variant_price in the where query just to give you idea what I want
Please help me to figure out its solution
Anyways i figured it out myself i needed to make join in the Product model so that Product.joins(:variants) after that in the scope I written
scope :with_min_range, lambda { |min|
where(" variants.price >= ?", "#{min.to_i}")
}
scope :with_max_range, lambda { |max|
where("variants.price <= ?", "#{max.to_i}")
}
it now successfully fetch the record based on minimum and maximum price
If anyone can give a better answer then please !
i am fairly new to rails and i have to update an existing project. I have an existing database, beforehand it was just one User group, now there should be multiple. Now i want to use the old view, but filter with the help of a dropdown menu, but for some reason i can't work out what i am doing wrong.
Here are the code snippets i changed, since it was working beforehand, i assume my mistake must be somewhere within these lines.
event.rb
scope :men, lambda { { :conditions => ["team_id == ?", 1] } }
scope :women, lambda { { :conditions => ["team_id == ?", 2] } }
scope :juniors, lambda { { :conditions => ["team_id == ?", 3] } }
events_controller.rb
def index
# #events = Event.where("startdate >= ?", Date.today).order("startdate, starttime")
# #events = Event.order("startdate, starttime")
if params[:search]
#events = Event.search(params[:search])
else
if params[:filter].nil?
#events = Event.all
else
if params[:filter] == "Alle" then #events = Event.all end
if params[:filter] == "Men" then #events = Event.men end
if params[:filter] == "Women" then #events = Event.women end
if params[:filter] == "Juniors" then #events = Event.juniors end
end
end
end
and the index.html.erb
<div class="left">
<%= form_tag events_path, :method => 'get' do %>
<%= select_tag "filter", options_for_select([ "Alle", "Men", "Women", "Juniors" ], params[:filter]), {:onchange => 'this.form.submit()'} %>
<% end %>
probably it is a simple mistake. My guess is, that in the index.html.erb i am doing something wrong.
as a follow up, i want to filter just the events which are upcoming, for that i can use the commented part in the controller. can i just add that to the assignmnet in the style of:
#events = Event.men.where("startdate >= ?", Date.today).order("startdate, starttime")
thanks for the help
Lenny
You should change your scopes to new syntax:
scope :men, -> { where(team_id: 1) }
scope :women, -> { where(team_id: 2) }
scope :juniors, -> { where(team_id: 3) }
Your controller logic is a little buggy and twisted (checking 5 times filter isnt best way, why checking e.g. if filter is "Men" if you already matched it with "Alle" ?). Here is some help:
#events = if params[:search].present?
Event.search(params[:search].to_s)
else
case params[:filter]
when "Men"
Event.men
when "Women"
Event.women
when "Juniors"
Event.juniors
else
Event.all
end
end
Speaking about view, you shouldnt use inline js, just because its XXI century, and such "quick solutions" are harder to maintain later, so:
<div class="left">
<%= form_tag events_path, :method => 'get' do %>
<%= select_tag "filter", options_for_select([ "Alle", "Men", "Women", "Juniors" ], params[:filter]), class: 'my_filter' %>
<% end %>
and then add to your events.coffee:
$('select.my_filter').on 'change', ->
$(this).parents('form').submit()
Hope this helps!
I got a problem defining new dynamic ProductFilters for Spree 2.0.4
My customer has got Categories (e.g. Taxons). A Product belongs to one category and has maximum 8 Properties BUT the Properties also depend on the Category each Product is in AND the Position of the Property is also important.
My Solution was to extend the Database in an unnormalized way:
module Spree
Taxon.class_eval do
belongs_to :prop1, class_name: "Spree::Property",
foreign_key: "p1_id"
belongs_to :prop2, class_name: "Spree::Property",
foreign_key: "p2_id"
belongs_to :prop3, class_name: "Spree::Property",
foreign_key: "p3_id"
belongs_to :prop4, class_name: "Spree::Property",
foreign_key: "p4_id"
belongs_to :prop5, class_name: "Spree::Property",
foreign_key: "p5_id"
belongs_to :prop6, class_name: "Spree::Property",
foreign_key: "p6_id"
belongs_to :prop7, class_name: "Spree::Property",
foreign_key: "p7_id"
belongs_to :prop8, class_name: "Spree::Property",
foreign_key: "p8_id"
attr_accessible :prop1, :prop2, :prop3, :prop4, :prop5, :prop6, :prop7, :prop8
def properties
prop = []
prop << prop1
prop << prop2
prop << prop3
prop << prop4
prop << prop5
prop << prop6
prop << prop7
prop << prop8
return prop
end
def applicable_filters
fs = []
fs << Spree::Core::ProductFilters.price_filter if Spree::Core::ProductFilters.respond_to?(:price_filter)
#fs << Spree::Core::ProductFilters.brand_filter if Spree::Core::ProductFilters.respond_to?(:brand_filter)
fs
end
end
end
So that I'm able to get the possible properties in a taxon for the corresponding product. I now made 8 Filters for each taxon property (prop1 .. prop8) because some values are numerical and should be handled different from text values, so even that's not completely DRY I came to the following solution:
module Spree
module Core
module ProductFilters
if Spree::Property.table_exists?
Spree::Product.add_search_scope :selective_prop1_any do |*opts|
conds = opts.map {|o| ProductFilters.selective_prop1_filter[:conds][o]}.reject {|c| c.nil?}
scope = conds.shift
conds.each do |new_scope|
scope = scope.or(new_scope)
end
Spree::Product.where(scope)
end
def ProductFilters.selective_prop1_filter(taxon = nil, locale = 'en')
return if taxon.nil? #||= Spree::Taxon.find_by_permalink!("categories")
property = taxon.prop1
scope = Spree::ProductProperty.where(:property_id => property, :locale => locale).
joins(:product => :taxons).
where("#{Spree::Taxon.table_name}.id" => [taxon] + taxon.descendants).
scoped
brands = scope.pluck(:value).uniq
{
:name => property.presentation,
:scope => :selective_prop1_any,
:labels => brands.sort.map { |k| [k,k] }
}
end
end
if Spree::Property.table_exists?
Spree::Product.add_search_scope :selective_prop2_any do |*opts|
conds = opts.map {|o| ProductFilters.selective_prop2_filter[:conds][o]}.reject {|c| c.nil?}
Rails.logger.debug conds.inspect
scope = conds.shift
Rails.logger.debug scope.inspect
conds.each do |new_scope|
scope = scope.or(new_scope)
end
Rails.logger.debug scope.inspect
Spree::Product.where(scope)
end
# ... other filters cut out for brevity
if Spree::Property.table_exists?
Spree::Product.add_search_scope :selective_prop8_any do |*opts|
[..]
end
def ProductFilters.selective_prop8_filter(taxon = nil, locale = 'en')
[..]
end
end
Spree::Product.add_search_scope :price_range_any do |*opts|
conds = opts.map {|o| Spree::Core::ProductFilters.price_filter[:conds][o]}.reject {|c| c.nil?}
scope = conds.shift
conds.each do |new_scope|
scope = scope.or(new_scope)
end
Spree::Product.joins(:master => :default_price).where(scope)
end
def ProductFilters.format_price(amount)
Spree::Money.new(amount)
end
def ProductFilters.price_filter
v = Spree::Price.arel_table
conds = [ [ Spree.t(:under_price, :price => format_price(10)) , v[:amount].lteq(10)],
[ "#{format_price(10)} - #{format_price(15)}" , v[:amount].in(10..15)],
[ "#{format_price(15)} - #{format_price(18)}" , v[:amount].in(15..18)],
[ "#{format_price(18)} - #{format_price(20)}" , v[:amount].in(18..20)],
[ Spree.t(:or_over_price, :price => format_price(20)) , v[:amount].gteq(20)]]
{ :name => Spree.t(:price_range),
:scope => :price_range_any,
:conds => Hash[*conds.flatten],
:labels => conds.map {|k,v| [k,k]}
}
end
end
end
end
Due to the fact, that even the values of the Properties should be localized, a made a column locale in the ProductProperties table. My selective filters pass the locale Variable to retrieve the correct ProductProperty.
Because of the MVC restrictions not being able to pass the locale from session[:locale] and the current taxon to the model I overwrote the original display logic which is using the applicable_filters method for the taxon in the CONTROLLER(!) like so:
TaxonsController.class_eval do
def show
#taxon = Taxon.find_by_permalink(params[:id])
return unless #taxon
if #taxon
#filters = []
#filters << Spree::Core::ProductFilters.selective_prop1_filter(#taxon, locale) unless #taxon.prop1.nil?
[...]
#filters << Spree::Core::ProductFilters.selective_prop8_filter(#taxon, locale) unless #taxon.prop8.nil?
#filters.concat(#taxon.applicable_filters)
else
#filters = Spree::Core::ProductFilters.all_taxons
end
p = params.merge(:taxon => #taxon.id)
#searcher = Spree::Config.searcher_class.new(params)
#searcher.current_user = try_spree_current_user
#searcher.current_currency = current_currency
#products = #searcher.retrieve_products
end
end
And here's the mainly left original view code:
<% unless #filters.empty? %>
<%= form_tag '', :method => :get, :id => 'sidebar_products_search' do %>
<% params[:search] ||= {} %>
<%= hidden_field_tag 'per_page', params[:per_page] %>
<% #filters.each do |filter| %>
<% labels = filter[:labels] || filter[:conds].map {|m,c| [m,m]} %>
<% next if labels.empty? %>
<div class="" data-hook="navigation">
<h5 class="filter-title"> <%= filter[:name] %> </h5>
<% labels.each do |nm,val| %>
<% label = "#{filter[:name]}_#{nm}".gsub(/\s+/,'_') %>
<label for="<%= label %>" class="checkbox" style="display:block;"><%= nm %><input type="checkbox"
id="<%= label %>"
name="search[<%= filter[:scope].to_s %>][]"
value="<%= val %>"
<%= params[:search][filter[:scope]] && params[:search][filter[:scope]].include?(val.to_s) ? "checked" : "" %> />
</label>
<% end %>
</div>
<% end %>
<%= submit_tag Spree.t(:search), :name => nil, :class => 'button' %>
<% end %>
<% end %>
The display works like it should: Depending on the taxon the user is in, the values from ProductProperties in the session[:locale] are fetched and displayed correctly, but now there comes the Problem:
The Search doesn't work work anymore. Even the not modified :price_range_any filter does not work. All Products belonging to the current taxon are always displayed. The search hash in params hash is built correct by the form search => {"price_range_any":["10.00 € EUR - 15.00 € EUR"]}
I've no idea. If I switch back to the original files by removing the overwrites everything is working.
How can I get my filters to run correctly?
How do I display previous/next links according to vehicle.vehicle_status
In my show view:
- if #vehicle.previous
= link_to "< Previous", #vehicle.previous
- if #vehicle.next
= link_to "Next >", #vehicle.next
In my model:
def previous
?
end
def next
?
end
vehicles/index.html.haml view:
- #vehicles.each do |vehicle|
%tr
%td.dashbox{:class => vehicle.vehicle_status, :style =>'width:18px;', :onclick=>"top.location=#{vehicle_url(vehicle)}"}
vehicle_status in model:
def vehicle_status
if self.maintenance_status=='c1' or self.fuel_efficiency_status=='c1' or self.system_status=='c1'
'c1'
elsif self.maintenance_status=='c2' or self.fuel_efficiency_status=='c2' or self.system_status=='c2'
'c2'
elsif self.maintenance_status=='c4' or self.fuel_efficiency_status=='c4' or self.system_status=='c4'
'c4'
else
'c3'
end
end
scope :previous, lambda { |vehicle|
where("vehicles.vehicle_status < ?", vehicle.vehicle_status).
order(:vehicle_status).reverse
}
scope :next, lambda { |vehicle|
where("vehicles.vehicle_status > ?", vehicle.vehicle_status).
order(:vehicle_status)
}
def previous
#previous ||= Vehicle.previous(self).first
end
def next
#next ||= Vehicle.next(self).first
end
In light of the fact that vehicle_status is a calculation and not a static field, and that there are other factors involved in the sorting, you can modify the scopes to look like this (using a helper method for the CASE string):
def self.vehicle_status_sql
<<-SQL
CASE
WHEN 'c1' IN (maintentance_status, fuel_efficiency_status, system_status) THEN 'c1'
WHEN 'c2' IN (maintentance_status, fuel_efficiency_status, system_status) THEN 'c2'
WHEN 'c4' IN (maintentance_status, fuel_efficiency_status, system_status) THEN 'c4'
ELSE 'c3'
END
SQL
end
scope :previous, lambda { |vehicle|
where("#{vehicle_status_sql} < :status OR (#{vehicle_status_sql} = :status AND (vehicles.odometer < :odometer OR (vehicles.odometer = :odometer AND vehicles.id < :id)))",
status: vehicle.vehicle_status, odometer: vehicle.odometer, id: vehicle.id).
order("#{vehicle_status_sql} DESC, vehicles.odometer DESC")
}
scope :next, lambda { |vehicle|
where("#{vehicle_status_sql} > :status OR ((#{vehicle_status_sql} = :status AND (vehicles.odometer > :odometer OR (vehicles.odometer = :odometer AND vehicles.id > :id)))",
status: vehicle.vehicle_status, odometer: vehicle.odometer, id: vehicle.id).
order("#{vehicle_status_sql}, vehicles.odometer)
}