Previous/Next links based on model's function - ruby-on-rails

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)
}

Related

How to call an active_model_serializer to serialize records explicitly

I have a serializer for a TimeEntry model that looks like this:
class TimeEntrySerializer < ActiveModel::Serializer
attributes :id, :description, :duration
has_one :project
end
And It works as expected when I just return all the records:
def index
#time_entries = current_user.time_entries.all
respond_to do |format|
format.html
format.json { render json: #time_entries }
end
end
However, I want to return the entries organized by day, something like this:
[
{ "2016-03-16" => [TimeEntry1, TimeEntry2, TimeEntry3] },
{ "2016-03-17" => [TimeEntry1, TimeEntry2] }
]
I do it like this form my model:
def self.get_entries_for_user(current_user)
current_user.time_entries
.group_by { |item| item.created_at.to_date.to_s }
.map { |day, entries| { day => entries } }
end
But now, the serializer is not working for the TimeEntry object, I'm not quite sure if it's actually supposed to work in this situation... I want to avoid having to format the data myself:
def self.get_entries_for_user(current_user)
current_user.time_entries
.group_by { |item| item.created_at.to_date.to_s }
.map do |day, entries|
{
day => entries.map do |entry|
{
:id => entry.id,
:description => entry.description,
:duration => entry.duration_ms,
:start_time => entry.time.begin,
:end_time => entry.time.end,
:project_id => entry.project.id
}
end
}
end
end
Is it possible to use the active_model_serializer for this situation? If not possible, how can I format the data more efficiently an avoid the nested map calls?
To call and be able to reuse the serializer:
options = {}
serialization = SerializableResource.new(resource, options)
serialization.to_json
serialization.as_json
So I used it like this:
def self.get_entries_for_user(current_user)
current_user.time_entries
.group_by { |item| item.created_at.to_date.to_s }
.map do |day, entries|
{
:day => day,
:entries => entries.map do |entry|
entry = ActiveModel::SerializableResource.new(entry)
entry.as_json
end
}
end
end

How to refactor ActiveRecord query?

I have a code in controller:
def latest
#latest_articles = user_signed_in? ? Article.limit(10).order(id: :desc).pluck(:id, :title) : Article.where("status = ?", Article.statuses[:public_article]).limit(10).order(id: :desc).pluck(:id, :title)
render json: #latest_articles
end
How to refactor it to looks elegant?
I tried using lambda:
extract = lambda {|a| a.order(id: :desc).pluck(:id, :title)}
Article.limit(10) {|a| a.extract}
but it returns only Article.limit(10)
UPD: I need to get last 10 of all articles if user is signed in, and last 10 of only public ones if not.
I would create an initial scope, and modify it based on some conditions:
def latest
scope = Article.order(id: :desc)
scope = scope.where(status: Article.statuses[:public_article]) if user_signed_in?
render json: scope.limit(10).pluck(:id, :title)
end
You could refactor as
#lates_articles = Article.all
#lates_articles = #latest_articles.where("status = ?", Article.statuses[:public_article]) unless user_signed_in?
render json: #latest_articles.limit(10).order(id: :desc).pluck(:id, :title)
But it would be better to create model method
class Article < ActiveRecord::Base
...
scope :latest, -> {last(10).order(id: :desc)}
def self.public user_signed
if user_signed
all
else
where("status = ?", statuses[:public_article])
end
end
...
end
Then you would use it like
def latest
render json: Article.public(user_signed_in?).latest.pluck(:id, :title)
end
final version:
def latest
scope = Article.order(id: :desc)
scope = scope.shared unless user_signed_in?
render json: scope.limit(10), except: [:body, :created_at, :updated_at]
end

Podio Ruby Rails shows "nomethoderror"

I'm having problems with the Podio_rails_sample. I've included my leadsController and leads.rb files. The line that gets hung up is field['config']['settings']['allowed_values'].
Line 25 is the problematic one:
NoMethodError in LeadsController#new
undefined method `[]' for nil:NilClass
Extracted source (around line #25):
23 app = Podio::Application.find(APP_ID)
24 field = app.fields.find { |field| field['external_id'] == 'status' }
25 field['config']['settings']['allowed_values']
26 end
27
28 def self.create_from_params(params)
Rails.root: c:/Sites/podio_rails_sample
app = Podio::Application.find(APP_ID)
field = app.fields.find { |field| field['external_id'] == 'status' }
field['config']['settings']['allowed_values']
end
def self.create_from_params(params)
Rails.root: c:/Sites/podio_rails_sample
-----------------------------------
class LeadsController < ApplicationController
before_filter :load_collections, :only => [:new, :edit]
def index
#leads = Lead.all
end
def new
#lead = Lead.new
end
def create
Lead.create_from_params(params['lead'])
redirect_to leads_path, :notice => 'Lead created'
end
def edit
#lead = Lead.find_basic(params[:id])
end
def update
Lead.update_from_params(params[:id], params['lead'])
redirect_to leads_path, :notice => 'Lead updated'
end
def destroy
Lead.delete(params[:id])
redirect_to leads_path, :notice => 'Lead deleted'
end
#protected
def load_collections
#lead_contacts = Lead.space_contacts
#sales_contacts = Lead.users
#statuses = Lead.statuses
end
end
-------------------------------------
- leads.rb file
class Lead < Podio::Item
APP_ID =12328033
SPACE_ID =3204114
# Find all items in the Leads app
def self.all
collection = self.find_all(APP_ID)
collection[:all]
end
# Find valid lead contacts in the space
def self.space_contacts
Podio::Contact.find_all_for_space(SPACE_ID, :order => 'contact', :limit => 12, :contact_type => 'space,connection', :exclude_self => false) rescue []
end
# Find valid sales contacts in the space
def self.users
Podio::Contact.find_all_for_space(SPACE_ID, :order => 'contact', :limit => 12, :contact_type => 'user', :exclude_self => false) rescue []
end
# Find valid statuses
def self.statuses
app = Podio::Application.find(APP_ID)
field = app.fields.find { |field| field['external_id'] == 'status' }
field['config']['settings']['allowed_values']
end
def self.create_from_params(params)
# raise fields.inspect
self.create(APP_ID, { :fields => fields_from_params(params) })
end
def self.update_from_params(id, params)
self.update(id, { :fields => fields_from_params(params) })
end
#
# Map the field values return by the Podio API to simple getters
#
def organization
field_values_by_external_id('company-or-organisation', :simple => true)
end
def lead_contact
field_values_by_external_id('contacts', :simple => true).try(:[], 'name')
end
def sales_contact
field_values_by_external_id('sales-contact', :simple => true).try(:[], 'name')
end
def potential_revenue_value
field_values_by_external_id('potential-revenue').try(:first).try(:[], 'value').to_i
end
def potential_revenue_currency
field_values_by_external_id('potential-revenue').try(:first).try(:[], 'currency')
end
def probability
field_values_by_external_id('probability-of-sale', :simple => true)
end
def status
field_values_by_external_id('status', :simple => true)
end
def followup_at
field_values_by_external_id('next-follow-up').try(:first).try(:[], 'start').try(:to_datetime)
end
protected
def field_values_by_external_id(external_id, options = {})
if self.fields.present?
field = self.fields.find { |field| field['external_id'] == external_id }
if field
values = field['values']
if options[:simple]
values.first['value']
else
values
end
else
nil
end
else
nil
end
end
def self.fields_from_params(params)
{
'company-or-organisation' => params[:organization],
'contacts' => (params[:lead_contact].present? ? params[:lead_contact].to_i : nil),
'sales-contact' => (params[:sales_contact].present? ? params[:sales_contact].to_i : nil),
'potential-revenue' => { :value => params['potential_revenue_value'], :currency => params['potential_revenue_currency'] },
'probability-of-sale' => params[:probability].to_i,
'status' => params[:status],
'next-follow-up' => DateTime.new(params['followup_at(1i)'].to_i, params['followup_at(2i)'].to_i, params['followup_at(3i)'].to_i).to_s(:db)
}.delete_if { |k, v| v.nil? }
end
end

How can validate params in the view?

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.

Scope is not recognizing both columns?

On my Tokeninput autocomplete field I am trying to make the returned columns be both my :address and :website when it goes by the defined :store method.
class BusinessStore < ActiveRecord::Base
scope :search_by_store, lambda { |q|
(q ? where(["address LIKE ? or website LIKE ? like ?", '%'+ q + '%', '%'+ q + '%','%'+ q + '%' ]) : {})}
def store
if self.online_store
"#{business_name} - #{website}"
else
"#{business_name} - #{address}"
end
end
end
class BusinessStoresController < ApplicationController
def index
#business_stores = BusinessStore.all
#business_stores = BusinessStore.search_by_store(params[:q])
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #business_stores }
format.json { render :json => #business_stores.collect{|b|{:id => b.id, :name => b.store } } }
end
end
end
My json page : http://localhost:3000/business_stores.json shows all the results correctly but the Token field only shows :address results and not website ones. How do I fix this?
Try this:
(q ? where(["address LIKE ? OR website LIKE ?", "%#{q}%", "%#{q}%" ]) : {})}

Resources