Very poor performance from ActiveAdmin - ruby-on-rails

I've recently imported around 50 000 records into an ActiveAdmin application and am now experiencing very poor performance. Is ActiveAdmin designed to handle this amount of records?
I have got slightly improved performance by adding in remove_filter for the filters I am not using.
I don't have any associations, which I know causes some performance issues. My model structure is completely flat with a couple of sub classes using single table inheritance.
I'm using:
ruby '2.1.1'
gem 'rails', '4.1.0'
gem 'activeadmin', github: 'activeadmin'
I've got the application deployed to Heroku. I've inserted some logs from Heroku down the bottom.
Here's my model code:
class Product < ActiveRecord::Base
# Scopes
scope :upward_trending, -> { where( "status > ?", 100) }
scope :downward_trending, -> { where( "status < ?", 100) }
scope :uncategorised, -> {where(category: '') }
scope :categorised, -> {where.not(category: '') }
end
Here's my resource code:
ActiveAdmin.register Product do
menu :label => "All Products", :priority => 1
config.clear_action_items!
permit_params :name, :link, :category, :image_url, :price, :interest, :interest_changes, :revenue, :start_date, :end_date, :company, :country, :price_eur, :price_gbp, :price_aud, :price_nzd, :price_cad
# Input
form do |f|
f.inputs 'Details' do
f.input :country, :as => :string
f.input :category
end
f.actions
end
# Scopes
scope :upward_trending, :default => true
scope :downward_trending
scope :all
# Default Sort
config.sort_order = "end_date_desc"
index do
column "Product Name", :sortable => :name do |a|
link_to a.name, a.link, :target => "_blank"
end
column "Image" do |a|
div :class => "image_url" do
link_to (image_tag a.image_url, class: 'image_url'), a.image_url, :target => "_blank", class: 'fancybox'
end
end
column "Price", :sortable => :price_eur do |a|
div :class => "number" do
case current_user.currency
when 'EUR'
number_to_currency(a.price_eur, unit: "€")
when 'GBP'
number_to_currency(a.price_gbp, unit: "£")
when 'AUD'
number_to_currency(a.price_aud, unit: "$")
when 'CAD'
number_to_currency(a.price_cad, unit: "$")
when 'NZD'
number_to_currency(a.price_nzd, unit: "$")
else
number_to_currency(a.price, unit: "$")
end
end
end
column "Status", :sortable => :status do |a|
div :class => "average" do
number_to_percentage(a.status, precision: 0)
end
end
column :category
column "Updated", :sortable => "end_date" do |a|
if a.end_date > Time.now - 5.days
distance_of_time_in_words(a.end_date, Time.now, include_seconds: true) + " ago"
else
a.end_date.to_formatted_s(:long)
end
end
#column :company
#column :country
end
# Sidebar
#sidebar :ProductSearch, :priority => 1 do
# render partial: 'admin/search_products', :locals => {:model_name => 'products'}
#end
# Filters
filter :category, :as => :check_boxes, :collection => proc { Product.all.collect {|dd| dd.category}.uniq.sort }
#filter :name, :label => "Product Name", :as => :string, filters: ['contains']
#filter :price, :label => "USD Price"
#filter :interest, :label => "Units Sold"
#filter :company, :as => :select, :collection => proc { Product.all.collect {|dd| dd.company}.uniq.sort }
filter :country, :as => :select, :collection => proc { Product.all.collect {|dd| dd.country}.uniq.sort }
filter :end_date, :label => "Date"
remove_filter :link
remove_filter :image_url
remove_filter :price
remove_filter :interest
remove_filter :interest_changes
remove_filter :revenue
remove_filter :start_date
remove_filter :price_eur
remove_filter :price_gbp
remove_filter :price_aud
remove_filter :price_nzd
remove_filter :price_cad
end
Here are some logs from Heroku when loading the resources, in this case it timed out.
2014-09-17T21:22:09.778167+00:00 app[web.1]: Started GET "/admin/products" for 91.226.23.198 at 2014-09-17 21:22:09 +0000
2014-09-17T21:22:09.786533+00:00 app[web.1]: Processing by Admin::ProductsController#index as HTML
2014-09-17T21:22:25.828163+00:00 heroku[web.1]: source=web.1 dyno=heroku.29301280.ba6942e6-4473-477d-8fa9-b3de141f9f06 sample#load_avg_1m=0.08 sample#load_avg_5m=0.09 sample#load_avg_15m=0.04
2014-09-17T21:22:25.828431+00:00 heroku[web.1]: source=web.1 dyno=heroku.29301280.ba6942e6-4473-477d-8fa9-b3de141f9f06 sample#memory_total=670.15MB sample#memory_rss=511.80MB sample#memory_cache=0.00MB sample#memory_swap=15
8.34MB sample#memory_pgpgin=352746pages sample#memory_pgpgout=221723pages
2014-09-17T21:22:25.829347+00:00 heroku[web.1]: Process running mem=670M(130.9%)
2014-09-17T21:22:25.829678+00:00 heroku[web.1]: Error R14 (Memory quota exceeded)
2014-09-17T21:22:39.775186+00:00 heroku[router]: at=error code=H12 desc="Request timeout" method=GET path="/admin/products" host=*.herokuapp.com request_id=e3abc8d7-f52d-47b2-bbb0-161823e1a596 fwd="91.226.23.198" d
yno=web.1 connect=1ms service=30001ms status=503 bytes=0
2014-09-17T21:22:40.763399+00:00 app[web.1]: E, [2014-09-17T21:22:40.714804 #2] ERROR -- : worker=0 PID:127 timeout (31s > 30s), killing
2014-09-17T21:22:41.133007+00:00 app[web.1]: E, [2014-09-17T21:22:41.132895 #2] ERROR -- : reaped #<Process::Status: pid 127 SIGKILL (signal 9)> worker=0
2014-09-17T21:22:43.505823+00:00 app[web.1]: I, [2014-09-17T21:22:43.491614 #158] INFO -- : worker=0 ready
2014-09-17T21:22:46.406853+00:00 heroku[router]: at=info method=GET path="/favicon.ico" host=x.herokuapp.com request_id=9769d818-5231-44db-ab19-d6f7597c308b fwd="91.226.23.198" dyno=web.1 connect=1ms service=5666ms
status=304 bytes=111
EDIT:
I've tried adding an index on end_date as am sorting descending with this. Unfortunately this made little change on the load times:
Sep 17 15:22:34 x app/web.1: Completed 200 OK in 8556ms (Views: 7377.9ms | ActiveRecord: 1173.7ms)
Sep 17 15:23:07 x app/web.1: Completed 200 OK in 8864ms (Views: 7640.8ms | ActiveRecord: 1220.0ms)
Sep 17 15:28:47 x app/web.1: Completed 200 OK in 9551ms (Views: 8039.2ms | ActiveRecord: 1442.5ms)
Sep 17 15:29:01 x app/web.1: Completed 200 OK in 8921ms (Views: 7651.1ms | ActiveRecord: 1264.0ms)

Looks like the culprit was this line of code:
filter :country, :as => :select, :collection => proc { Product.all.collect {|dd| dd.country}.uniq.sort }
Changed it to:
filter :country, :as => :select, :collection => proc { Product.pluck(:country).uniq.sort }

Related

A workaround to pre-populate file_field?

I don't think you can literally pre-populate the file_field so I've been struggling with a workaround for the same end goal, which is to take an image already uploaded to the application via User A and then for User B to be able to save that same image as his own too, similar to pinterest.
This is what I've tried:
index
<%= link_to new_inspiration_path(inspiration_image: inspiration.image) %>
controller
def new
#inspiration = current_user.inspirations.build
#inspiration.image = URI.parse(params[:inspiration_image])
end
server
Started GET "/inspirations/new?inspiration_image=%2Fsystem%2Finspirations%2Fimages%2F000%2F000%2F069%2Foriginal%2Frule_1.jpg%3F1478260961" for 127.0.0.1 at 2016-11-04 08:10:41 -0400
Processing by InspirationsController#new as */*
Parameters: {"inspiration_image"=>"/system/inspirations/images/000/000/069/original/rule_1.jpg?1478260961"} # For example, this is the image url I'm trying to duplicate for User B
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 129]]
Inspiration Load (0.4ms) SELECT "inspirations".* FROM "inspirations" WHERE "inspirations"."id" IS NULL LIMIT 1
Completed 400 Bad Request in 6ms
_form
<%= simple_form_for(#inspiration, html: { data: { modal: true } }) do |f| %>
<%= image_tag #inspiration.image.url if #inspiration.image.present? %> # I get error: ActionController::ParameterMissing (param is missing or the value is empty: inspiration):
<%= f.file_field :image %>
<% end %>
model
class Inspiration < ActiveRecord::Base
has_attached_file :image, :styles => { :medium => "300x300>", :small => "150x150>" }
validates_attachment_content_type :image, :content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif"]
belongs_to :user
def image_remote_url=(url_value)
self.image = URI.parse(url_value).to_s unless url_value.blank?
super
end
end
Change #inspiration.image assignment to #inspiration.image = URI.parse(params[:inspiration_image])
More info can be found here: https://github.com/thoughtbot/paperclip/wiki/Attachment-downloaded-from-a-URL
EDIT:
Change model according to the info in the link:
attr_reader :image_remote_url
#image_remote_url = url_value
Remove super call
Change assignment to #inspiration.image_remote_url = params[:inspiration_image]

Sidekiq job not being queued

There is a chain of state machine callbacks that invoke ActiveJob::Base classes to process sequential phases of an order lifecycle.
I am running into a problem where the second job in the sequence is not being enqueued and no errors are being printed to the terminal.
The second job is
class WriteEncodedPreviewImageToFilesJob < ActiveJob::Base
queue_as :imagery_queue
def perform(order)
run_phase_of_order_lifecycle(order)
end
private
def run_phase_of_order_lifecycle(order)
begin
BackgroundWorkers::EncodedPreviewImageWriter.work(order)
ensure
order.render_final_image
end
end
end
And it is being invoked here:
class PreAuthorizeStripePaymentJob < ActiveJob::Base
queue_as :stripe_queue
def perform(order)
run_phase_of_order_lifecycle(order)
end
private
def run_phase_of_order_lifecycle(order)
response = create_stripe_charge(order)
if response['failure_code'] == nil
order.stripe_charge_id = response['id']
order.save!
order.write_encoded_preview_image_to_files # this line here!!!
end
response
end
def create_stripe_charge(order)
Stripe::Charge.create(
:amount => (order.original[:order][:price] * 100).round,
:currency => 'gbp',
:capture => false,
:source => order.stripe_id,
:description => "Charge for Order with id: #{order.id}",
:receipt_email => order.original[:order][:user_email]
)
end
end
Because of the callback defined in this module (please scroll down):
module OrderLifecycle
extend ActiveSupport::Concern
include ActiveSupport::Callbacks
included do
state_machine :initial => :pending do
# States
event :pre_authorize_stripe_payment do
transition :pending => :stripe_payment_pre_authorized
end
event :write_encoded_preview_image_to_files do
transition :stripe_payment_pre_authorized => :encoded_preview_image_written_to_files # this line here!!! and...
end
event :render_final_image do
transition :encoded_preview_image_written_to_files => :final_image_rendered
end
event :upload_composition_to_parse do
transition :final_image_rendered => :composition_uploaded_to_parse
end
event :upload_print_file_to_printer do
transition :composition_uploaded_to_parse => :print_file_uploaded_to_printer
end
event :call_to_process_message do
transition :print_file_uploaded_to_printer => :process_message_called
end
event :capture_stripe_payment do
transition :process_message_called => :stripe_payment_captured
end
event :mark_as_complete do
transition :stripe_payment_captured => :complete
end
# Callbacks
before_transition :on => :pre_authorize_stripe_payment do |order|
PreAuthorizeStripePaymentJob.perform_later order
end
before_transition :on => :write_encoded_preview_image_to_files do |order|
WriteEncodedPreviewImageToFilesJob.perform_later order # this line here!!!
end
before_transition :on => :render_final_image do |order|
RenderFinalImageJob.perform_later order
end
before_transition :on => :upload_composition_to_parse do |order|
UploadCompositionToParseJob.perform_later order
end
before_transition :on => :upload_print_file_to_printer do |order|
UploadPrintFileToPrinterJob.perform_later order
end
before_transition :on => :call_to_process_message do |order|
CallToProcessMessageJob.perform_later order
end
before_transition :on => :capture_stripe_payment do |order|
CaptureStripePaymentJob.perform_later order
end
end
end
end
My config/sidekiq.yml is
---
:verbose: true
:queues:
- imagery_queue
- parse_queue
- stripe_queue
- printer_api_queue
When I start Sidekiq initially the output to the terminal is:
2015-12-14T03:00:25.339Z 7664 TID-akza0 INFO: Booting Sidekiq 3.5.0 with redis options {:url=>"redis://localhost:6379"}
m,
`$b
.ss, $$b .,d$
`$$P,d$P' .,md$$P' ____ _ _ _ _
,$$$$$$bmmd$$$^' / ___|(_) __| | ___| | _(_) __ _
,d$$$$$$$$$$$P \___ \| |/ _` |/ _ \ |/ / |/ _` |
$s^' `"^$$$' ___) | | (_| | __/ <| | (_| |
$: ,$$P |____/|_|\__,_|\___|_|\_\_|\__, |
`b :$$ |_|
$$:
$$
.d$$
2015-12-14T03:00:28.076Z 7664 TID-akza0 INFO: Running in ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]
2015-12-14T03:00:28.077Z 7664 TID-akza0 INFO: See LICENSE and the LGPL-3.0 for licensing details.
2015-12-14T03:00:28.077Z 7664 TID-akza0 INFO: Upgrade to Sidekiq Pro for more features and support: http://sidekiq.org
2015-12-14T03:00:28.091Z 7664 TID-akza0 DEBUG: Middleware: Sidekiq::Middleware::Server::Logging, Sidekiq::Middleware::Server::RetryJobs, Sidekiq::Middleware::Server::ActiveRecord
2015-12-14T03:00:28.091Z 7664 TID-akza0 INFO: Starting processing, hit Ctrl-C to stop
2015-12-14T03:00:28.104Z 7664 TID-wjesw DEBUG: {:queues=>["imagery_queue", "parse_queue", "stripe_queue", "printer_api_queue"], :labels=>[], :concurrency=>25, :require=>".", :environment=>nil, :timeout=>8, :poll_interval_average=>nil, :average_scheduled_poll_interval=>15, :error_handlers=>[#<Sidekiq::ExceptionHandler::Logger:0x00000002a28dc8>], :lifecycle_events=>{:startup=>[], :quiet=>[], :shutdown=>[]}, :dead_max_jobs=>10000, :dead_timeout_in_seconds=>15552000, :verbose=>true, :config_file=>"config/sidekiq.yml", :strict=>true, :tag=>"xxxxxxxxx"}
The problem was in calling the write_encoded_preview_image_to_files method prematurely. Substituting write_encoded_preview_image_to_files! and inserting a binding.pry revealed:
9: def run_phase_of_order_lifecycle(order)
10: response = create_stripe_charge(order)
11: if response['failure_code'] == nil
12: order.stripe_charge_id = response['id']
13: order.save!
14: binding.pry
15: order.write_encoded_preview_image_to_files!
16: end
=> 17: response
18: end
[1] pry(#<PreAuthorizeStripePaymentJob>)> order.state
=> "pending"
[2] pry(#<PreAuthorizeStripePaymentJob>)> order.write_encoded_preview_image_to_files!
StateMachines::InvalidTransition: Cannot transition state via :write_encoded_preview_image_to_files from :pending (Reason(s): State cannot transition via "write encoded preview image to files")
from /home/*****/.rvm/gems/ruby-2.2.2/gems/state_machines-0.4.0/lib/state_machines/event.rb:224:in `block in add_actions'
[3] pry(#<PreAuthorizeStripePaymentJob>)> order.write_encoded_preview_image_to_files
Then checking the order's state in the rails console after the job had been processed:
2.2.2 :044 > Order.last.state
Order Load (1.2ms) SELECT "orders".* FROM "orders" ORDER BY "orders"."id" DESC LIMIT 1
=> "stripe_payment_pre_authorized"
2.2.2 :045 >
Therefore this problem may be solved by adding the following callback to the OrderLifecycle module:
after_transition :on => :pre_authorize_stripe_payment do |order|
order.write_encoded_preview_image_to_files
end

how to load and validate the video using paperclip-Rails

please help solve the problem.
using a paperclip I organized upload images. it works.
Now I would like to organize a video upload. I changed this model:
model:
class Video < ActiveRecord::Base
validates :title, presence: true
validates :video, presence: true
belongs_to :user
has_attached_file :video,
:styles => { :medium => "300x300>", :thumb => "100x100>" },
:default_url => "/images/:style/missing.png"
validates_attachment_content_type :video, :content_type => /\Avideo\/.*\Z/
validates_attachment_file_name :video, :matches => [/3gp\Z/, /mp4\Z/, /flv\Z/]
validate :file_size_validation, :if => "video?"
def file_size_validation
errors[:video] << "should be less than 2MB" if video.size.to_i > 30.megabytes
end
end
video controller:
def create
#video = Video.new(video_params)
if #video.save
#video.update_attributes(user: current_user)
flash[:success] = :video_created
redirect_to #video
else
flash.now[:error] = :user_not_created
render 'new'
end
end
form:
<%= form_for(#video) do |f| %>
<%= f.text_field :title %>
<%= f.file_field :video %>
<%= f.submit %>
<% end %>
after attempting to upload the video I get the console the following error message:
Started POST "/videos" for 127.0.0.1 at 2015-07-23 14:17:32 +0300
Processing by VideosController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"RF3w8PzZ9LZ4pdqRPqRvHMQ+nYDL4om0YHAMlzTm8tf3iFmVmKxXSYKap3C0ogEnOkifm9i01oXs/rTX9zmtPA==", "video"=>{"title"=>"tty", "video"=>#<ActionDispatch::Http::UploadedFile:0x007f6624f10770 #tempfile=#<Tempfile:/tmp/RackMultipart20150723-13428-u7s8i8.flv>, #original_filename="mmm.flv", #content_type="video/x-flv", #headers="Content-Disposition: form-data; name=\"video[video]\"; filename=\"mmm.flv\"\r\nContent-Type: video/x-flv\r\n">}, "commit"=>"Create Video"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["id", 8]]
Command :: file -b --mime '/tmp/c4efd5020cb49b9d3257ffa0fbccc0ae20150723-13428-6gn39i.flv'
Command :: identify -format '%wx%h,%[exif:orientation]' '/tmp/c4efd5020cb49b9d3257ffa0fbccc0ae20150723-13428-1eailfd.flv[0]' 2>/dev/null
[paperclip] An error was received while processing: #<Paperclip::Errors::NotIdentifiedByImageMagickError: Paperclip::Errors::NotIdentifiedByImageMagickError>
Command :: identify -format '%wx%h,%[exif:orientation]' '/tmp/c4efd5020cb49b9d3257ffa0fbccc0ae20150723-13428-1eailfd.flv[0]' 2>/dev/null
[paperclip] An error was received while processing: #<Paperclip::Errors::NotIdentifiedByImageMagickError: Paperclip::Errors::NotIdentifiedByImageMagickError>
(0.2ms) BEGIN
Command :: file -b --mime '/tmp/c4efd5020cb49b9d3257ffa0fbccc0ae20150723-13428-khstwa.flv'
(0.2ms) ROLLBACK
on screen displays the following error message:
Video Paperclip::Errors::NotIdentifiedByImageMagickError
wherein imageMagik installed in my system:
sudo apt-get install imagemagick
db:
create_table "videos", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "title"
t.integer "user_id"
t.string "video_file_size"
t.string "video_updated_at"
t.string "video_file_name"
t.string "video_content_type"
end
Working with image with paperclip and with video is different.Though the common point is that it will help you tu send the uploaded data to the server but you need to handle it with some processor.Just like you use ImageMagick for images,you should use FFMPEG to encode/decode video.
i will share the code which i usually use for video..but before that ,you must set up ffmpeg to handle all formats of video just like you did for Imagemagick.
here is set up for ffmpeg and dont forget to provide path in environment file using which ffmpeg
you need ffmpeg-paperclip as well for coding/decoding videos.
video.rb
##using s3
##convert the video into mp4 and also get screenshot of video at 5 sec
##add your own formats that you want
has_attached_file :video,
:styles => {
:mp4video => { :geometry => '520x390', :format => 'mp4',
:convert_options => { :output => { :vcodec => 'libx264',
:vpre => 'ipod640', :b => '250k', :bt => '50k',
:acodec => 'libfaac', :ab => '56k', :ac => 2 } } },
:preview => { :geometry => '300x300>', :format => 'jpg', :time => 5 }
},
processors: [:ffmpeg],
:storage => :s3,
:size => { :in => 0..25.megabytes },
:s3_permissions => :public_read,
:s3_credentials => S3_CREDENTIALS
validates_attachment_content_type :video, :content_type => /\Avideo\/.*\Z/
validates_presence_of :video
once you have saved the video,you need to use some plugins to show the video player along with your video in show action.You can use Mediaelement.js(my favorite).Download it,dump it in js/css files accordingly,Include it in application.js and application.css.
in your show.html.erb
##add video tag to show video
<video autobuffer="autobuffer" preload="auto" style="width:100%;height:100%;" controls="controls" width="100%" height="100%" poster="<%= #video.video.url(:preview)%>" >
<source src="<%= #video.video.url%>" />
<%if #video.video.expiring_url(:mp4video).present? %>
<source type="video/mp4" src="<%= #video.video.url(:mp4video)%>" />
<%end%>
</video>
##javascript to handle video player
$('video').mediaelementplayer();
paperclip's processor is designed for images, so it cannot handle videos. You're getting the error saying that ImageMagick did not recognize this file as an image. Fair enough, it's not an image!
Still, you could write a post-processor yourself, and paperclip's github page offers an example of the syntax that would be needed to call a custom processing class:
has_attached_file :scan, :styles => { :text => { :quality => :better } },
:processors => [:ocr]
This defines a variation of the attachment called text that is obtained by processing the uploaded file with a (hypothetical) Paperclip::Ocr class with options hash { :quality => :better }
Choice of the exact conversion tool is up to you, but you do want to make sure that processing is done asynchronously, not inside the usual request-response cycle, you may want to use a background queue like Sidekiq, Que or Rails' (4.2+) ActiveJob.

Add a new search field and filter result as per the value of the filed in Spree

I want to filter the orders using stock_location field. I have the added the field to the filter section:
# app/overrides/admin.rb
Deface::Override.new(:virtual_path => "spree/admin/orders/index",
:name => "stock_locations",
:insert_top => "div.omega.four.columns",
:text => "<%= label_tag :q_line_items_variant_stock_locations_id_eq, 'Stock Locations' %><%= f.select :line_items_variant_stock_locations_id_eq, Spree::StockLocation.pluck(:id, :name).collect { |id, name| [name.strip, id]}, {:include_blank => true}, :class => 'select2 js-filterable'")
From UI, the value of the stock location is being passed, but the result is displaying all orders.
production log
==> log/thin.3001.log <==
Started GET "/admin/orders?utf8=%E2%9C%93&q%5Bcreated_at_gt%5D=&q%5Bcreated_at_lt%5D=&q%5Bstate_eq%5D=&q%5Bnumber_cont%5D=&q%5Bemail_cont%5D=&q%5Bbill_address_firstname_start%5D=&q%5Bbill_address_lastname_start%5D=&q%5Bline_items_variant_stock_locations_id_eq%5D=10&q%5Bcompleted_at_not_null%5D=0&q%5Bpromotions_id_in%5D=&button=" for 127.0.0.1 at 2015-02-12 07:57:41 +0000
Processing by Spree::Admin::OrdersController#index as HTML
Parameters: {"utf8"=>"✓", "q"=>{"created_at_gt"=>"", "created_at_lt"=>"", "state_eq"=>"", "number_cont"=>"[FILTERED]", "email_cont"=>"", "bill_address_firstname_start"=>"", "bill_address_lastname_start"=>"", "line_items_variant_stock_locations_id_eq"=>"4", "completed_at_not_null"=>"0", "promotions_id_in"=>""}, "button"=>""}
Rendered /home/deploy/.rvm/gems/ruby-2.1.2/bundler/gems/spree-080df18614ba/backend/app/views/spree/admin/orders/index.html.erb within spree/layouts/admin (212.6ms)
Rendered /home/deploy/.rvm/gems/ruby-2.1.2/bundler/gems/spree-080df18614ba/backend/app/views/spree/admin/shared/_translations.html.erb (4.7ms)
Rendered /home/deploy/.rvm/gems/ruby-2.1.2/bundler/gems/spree-080df18614ba/backend/app/views/spree/admin/shared/_head.html.erb (6.5ms)
In my console I am seeing less data than I am seeing from UI. Basically, in UI it seems filtering is not working.
2.1.2 :005 > Spree::Order.ransack(line_items_variant_stock_locations_id_eq: 4).result.to_a.count
=> 156
2.1.2 :015 > y Spree::Order.ransackable_associations
---
- user
- created_by
- approver
- bill_address
- ship_address
- state_changes
- line_items
- payments
- return_authorizations
- adjustments
- line_item_adjustments
- shipment_adjustments
- inventory_units
- products
- variants
- promotions
- shipments
=> nil
I had used wrong associations. Working code is:
Deface::Override.new(:virtual_path => "spree/admin/orders/index",
:name => "stock_locations",
:insert_top => "div.omega.four.columns",
:text => "<%= label_tag :q_shipments_stock_location_id_eq, 'Stock Locations' %><%= f.select :shipments_stock_location_id_eq, Spree::StockLocation.pluck(:id, :name).collect { |id, name| [name.strip, id]}, {:include_blank => true}, :class => 'select2 js-filterable'")
This is how I went to the final Ransack attribute naming, which does the query internally.
2.1.2 :016 > o = Spree::Order.find_by_number('R482860025')
=> #<Spree::Order id: 144, ...>
2.1.2 :020 > o.shipments.first.stock_location.name
=> "Warehouse"
2.1.2 :020 > o.shipments.first.stock_location.id
=> "4"

Heroku - ActiveRecord::StatementInvalid (PG::Error: ERROR: column "requested" does not exist

I have an absense.html.erb which works fine in development and production. However when I try to access the page I get the following error:
2013-03-25T18:43:43+00:00 app[web.1]: Started GET "/absence" for
77.100.90.77 at 2013-03-25 18:43:43 +0000 2013-03-25T18:43:43+00:00 app[web.1]: 2013-03-25T18:43:43+00:00 app[web.1]:
ActiveRecord::StatementInvalid (PG::Error: ERROR: column "requested"
does not exist 2013-03-25T18:43:43+00:00 app[web.1]: LINE 1: ...LECT
"holidays".* FROM "holidays" WHERE (state = "requested...
2013-03-25T18:43:43+00:00 app[web.1]:
^ 2013-03-25T18:43:43+00:00 app[web.1]: : SELECT "holidays".* FROM
"holidays" WHERE (state = "requested")): 2013-03-25T18:43:43+00:00
app[web.1]: 2013-03-25T18:43:43+00:00 app[web.1]:
2013-03-25T18:43:43+00:00 app[web.1]:
app/controllers/holidays_controller.rb:52:in `absence'
2013-03-25T18:43:43+00:00 heroku[router]: at=info method=GET
path=/rota_days host=miuk-portal.herokuapp.com fwd="77.100.90.77"
dyno=web.1 queue=0 wait=0ms connect=1ms service=5773ms status=200
bytes=897173
The error points to the following line of my absense method in my controller
def absence
#show the holidays where the approver id matches the current user id
#and state = "requested"'
#user = current_user
if current_user.role? :administrator
# a superadmin can view all current holiday requests
#holidays = Holiday.find(:all, :conditions => 'state = "requested"')
else
#otherwise an admin sees the holiday requests that they are approvers for
#holidays = Holiday.find(:all, :conditions => ["approver_id = #{current_user.id}", "state = requested"])
end
end
I have declared this in my holiday model as shown below:
Holiday.rb
class Holiday < ActiveRecord::Base
belongs_to :user
belongs_to :calendar
belongs_to :type, :class_name => "Type"
belongs_to :approver, :class_name => "User"
before_create :default_values #Before creating holiday set default_values
#before_create :overflow
validates :start_at, :presence => { :message => "must be a valid date/time" }
validates :end_at, :presence => {:message => "must be a valid date/time"}
validate :start_must_be_before_end_date
validate :overflow #Hook method to determine if user holidays are over the set amount
validates_presence_of :end_at, :start_at
attr_accessible :description, :end_at, :start_at, :state, :type_id, :user_id, :color
def length
(self.end_at.to_i - self.start_at.to_i)/(60*60*24)
end
def days_used
( (start_at.to_date)..(end_at.to_date) ).select {|d| (1..5).include?(d.wday) }.size
end
#Validates_presence_of is called to ensure that the start date exisit.
#Start date must be lt or = to end date otherwise throw error.
def start_must_be_before_end_date
errors.add(:start_at, "must be before end date") unless
self.start_at <= self.end_at
end
#Overflow of holidays is validated by calling "validates" L31. Then checks if absent days
#Is gt or = to length
def overflow
errors.add(:overflow, "- You only have #{user.absentdays} days holiday remaining; this absence is #{length} days.") unless
user.absentdays >= length
end
def name
return self.user.name
end
def colors
if state ||= "denied"
return self.color ||= "#C00000"
end
end
private
#Setting default values - before_create is called and sets the following
def default_values
self.state ||= "requested"
self.color ||= "#000000"
self.type_id||= 1
end
end
Don't seem to understand why this works in both development and production and not in heroku. Any ideas?
Standard SQL strings use single quotes, double quotes are for identifiers (such as table and column names); PostgreSQL follows the standard here, MySQL and SQLite are less strict, other databases do other things with varying amounts of strictness. In any case, single quotes for SQL string literals should work the same everywhere.
You're using double quotes on an SQL string:
#holidays = Holiday.find(:all, :conditions => 'state = "requested"')
#------------------------------------------------------^---------^
You must single quotes:
#holidays = Holiday.find(:all, :conditions => %q{state = 'requested'})
or modernize it and let ActiveRecord deal with the quoting:
#holidays = Holiday.where(:state => 'requested')
You'll probably need to fix the quoting for this one too:
#holidays = Holiday.find(:all, :conditions => ["approver_id = #{current_user.id}", "state = requested"])
Again, modernizing it is the easiest way:
#holidays = Holiday.where(:approver_id => current_user.id, :state => 'requested')
I'm guessing that you're developing on SQLite but deploying on PostgreSQL. That's a bad idea, always develop and deploy on the same stack.

Resources