Using Rails 4 and Ruby 1.9.3.
I have this view in usuarios#show I'm rendering. The controller demands a lot of data, but I have managed to reduce the queries with eager_load and akin from 300ms odd to a 44 ms.
My problem is that the database call is ok, but the views are taking close to 30 seconds to render.
I have made sure that I'm getting everything I use from the controller variables.
EDIT: I have added the query itself from the controller
This is the controller method, using eager_loading
#app/controllers/usuarios_controller.rb
before_action :show_usuario, only: [:show]
def show
if !#usuario.country_id.blank?
#country = #usuario.country
end
respond_to do |format
format.html
format.js
end
end
private
def show_usuario
if usuario_signed_in?
id = current_usuario.id
#usuario = Usuario.eager_load(:profile).find(id)
else
#usuario = Usuario.eager_load(:profile, textos: [:likes, :text_medals, :tags]).find(params[:id])
end
#textos = Texto.eager_load(:likes, :text_medals, :tags).where(:usuario_id => #usuario.id).order("textos.created_at DESC").paginate(:page => params[:page]).per_page(6)
end
Here is my log
Started GET "/" for 127.0.0.1 at 2014-03-25 12:55:39 +0100
Usuario Load (1.4ms) SELECT "usuarios".* FROM "usuarios" WHERE "usuarios"."id" = 12 ORDER BY "usuarios"."id" ASC LIMIT 1
Processing by UsuariosController#show as HTML
Notification Load (1.2ms) SELECT "notifications".* FROM "notifications" INNER JOIN "textos" ON "textos"."id" = "notifications"."text" WHERE (textos.usuario_id = 12 AND notifications.user_related != 12) ORDER BY "notifications"."id" DESC LIMIT 10
SQL (1.2ms) SELECT "usuarios"."id" AS t0_r0, "usuarios"."email" AS t0_r1, "usuarios"."encrypted_password" AS t0_r2, "usuarios"."reset_password_token" AS t0_r3, "usuarios"."reset_password_sent_at" AS t0_r4, "usuarios"."remember_created_at" AS t0_r5, "usuarios"."sign_in_count" AS t0_r6, "usuarios"."current_sign_in_at" AS t0_r7, "usuarios"."last_sign_in_at" AS t0_r8, "usuarios"."current_sign_in_ip" AS t0_r9, "usuarios"."last_sign_in_ip" AS t0_r10, "usuarios"."created_at" AS t0_r11, "usuarios"."updated_at" AS t0_r12, "usuarios"."nombre" AS t0_r13, "usuarios"."fecha_nac" AS t0_r14, "usuarios"."country_id" AS t0_r15, "usuarios"."is_admin" AS t0_r16, "usuarios"."publish_fbviews" AS t0_r17, "usuarios"."accept_terms" AS t0_r18, "profiles"."id" AS t1_r0, "profiles"."usuario_id" AS t1_r1, "profiles"."quote" AS t1_r2, "profiles"."quote_author" AS t1_r3, "profiles"."fb_account" AS t1_r4, "profiles"."twt_account" AS t1_r5, "profiles"."gpls_account" AS t1_r6, "profiles"."biografia" AS t1_r7, "profiles"."created_at" AS t1_r8, "profiles"."updated_at" AS t1_r9, "profiles"."hide_email" AS t1_r10, "profiles"."pic_file_name" AS t1_r11, "profiles"."pic_content_type" AS t1_r12, "profiles"."pic_file_size" AS t1_r13, "profiles"."pic_updated_at" AS t1_r14 FROM "usuarios" LEFT OUTER JOIN "profiles" ON "profiles"."usuario_id" = "usuarios"."id" WHERE "usuarios"."id" = $1 LIMIT 1 [["id", 12]]
USER CARGADO
Country Load (0.7ms) SELECT "countries".* FROM "countries" WHERE "countries"."id" = $1 LIMIT 1 [["id", 246]]
TEXTOS CARGADOS
Rendered usuarios/_main_frame.html.erb (12082.9ms)
(1.6ms) SELECT COUNT(DISTINCT "textos"."id") FROM "textos" LEFT OUTER JOIN "likes" ON "likes"."texto_id" = "textos"."id" LEFT OUTER JOIN "text_medals_textos" ON "text_medals_textos"."texto_id" = "textos"."id" LEFT OUTER JOIN "text_medals" ON "text_medals"."id" = "text_medals_textos"."text_medal_id" LEFT OUTER JOIN "tags_textos" ON "tags_textos"."texto_id" = "textos"."id" LEFT OUTER JOIN "tags" ON "tags"."id" = "tags_textos"."tag_id" WHERE "textos"."usuario_id" = 12
SQL (1.9ms) SELECT DISTINCT "textos".id, textos.created_at AS alias_0 FROM "textos" LEFT OUTER JOIN "likes" ON "likes"."texto_id" = "textos"."id" LEFT OUTER JOIN "text_medals_textos" ON "text_medals_textos"."texto_id" = "textos"."id" LEFT OUTER JOIN "text_medals" ON "text_medals"."id" = "text_medals_textos"."text_medal_id" LEFT OUTER JOIN "tags_textos" ON "tags_textos"."texto_id" = "textos"."id" LEFT OUTER JOIN "tags" ON "tags"."id" = "tags_textos"."tag_id" WHERE "textos"."usuario_id" = 12 ORDER BY textos.created_at DESC LIMIT 6 OFFSET 0
SQL (5.6ms) SELECT "textos"."id" AS t0_r0, "textos"."usuario_id" AS t0_r1, "textos"."titulo" AS t0_r2, "textos"."contenido" AS t0_r3, "textos"."idioma" AS t0_r4, "textos"."created_at" AS t0_r5, "textos"."updated_at" AS t0_r6, "textos"."is_borrador" AS t0_r7, "textos"."is_on_contest" AS t0_r8, "textos"."portada_file_name" AS t0_r9, "textos"."portada_content_type" AS t0_r10, "textos"."portada_file_size" AS t0_r11, "textos"."portada_updated_at" AS t0_r12, "textos"."contest_id" AS t0_r13, "textos"."views" AS t0_r14, "textos"."has_draft" AS t0_r15, "textos"."license_type" AS t0_r16, "likes"."id" AS t1_r0, "likes"."usuario_id" AS t1_r1, "likes"."texto_id" AS t1_r2, "likes"."created_at" AS t1_r3, "likes"."updated_at" AS t1_r4, "text_medals"."id" AS t2_r0, "text_medals"."name" AS t2_r1, "text_medals"."slogan" AS t2_r2, "text_medals"."created_at" AS t2_r3, "text_medals"."updated_at" AS t2_r4, "text_medals"."image_file_name" AS t2_r5, "text_medals"."image_content_type" AS t2_r6, "text_medals"."image_file_size" AS t2_r7, "text_medals"."image_updated_at" AS t2_r8, "tags"."id" AS t3_r0, "tags"."nombre" AS t3_r1, "tags"."created_at" AS t3_r2, "tags"."updated_at" AS t3_r3 FROM "textos" LEFT OUTER JOIN "likes" ON "likes"."texto_id" = "textos"."id" LEFT OUTER JOIN "text_medals_textos" ON "text_medals_textos"."texto_id" = "textos"."id" LEFT OUTER JOIN "text_medals" ON "text_medals"."id" = "text_medals_textos"."text_medal_id" LEFT OUTER JOIN "tags_textos" ON "tags_textos"."texto_id" = "textos"."id" LEFT OUTER JOIN "tags" ON "tags"."id" = "tags_textos"."tag_id" WHERE "textos"."usuario_id" = 12 AND "textos"."id" IN (75, 74, 73, 70, 69, 68) ORDER BY textos.created_at DESC
CACHE (0.0ms) SELECT COUNT(DISTINCT "textos"."id") FROM "textos" LEFT OUTER JOIN "likes" ON "likes"."texto_id" = "textos"."id" LEFT OUTER JOIN "text_medals_textos" ON "text_medals_textos"."texto_id" = "textos"."id" LEFT OUTER JOIN "text_medals" ON "text_medals"."id" = "text_medals_textos"."text_medal_id" LEFT OUTER JOIN "tags_textos" ON "tags_textos"."texto_id" = "textos"."id" LEFT OUTER JOIN "tags" ON "tags"."id" = "tags_textos"."tag_id" WHERE "textos"."usuario_id" = 12
Usuario Load (0.8ms) SELECT "usuarios".* FROM "usuarios" WHERE "usuarios"."id" = $1 ORDER BY "usuarios"."id" ASC LIMIT 1 [["id", 12]]
Profile Load (0.7ms) SELECT "profiles".* FROM "profiles" WHERE "profiles"."usuario_id" = $1 ORDER BY "profiles"."id" ASC LIMIT 1 [["usuario_id", 12]]
CACHE (0.1ms) SELECT "usuarios".* FROM "usuarios" WHERE "usuarios"."id" = $1 ORDER BY "usuarios"."id" ASC LIMIT 1 [["id", 12]]
CACHE (0.0ms) SELECT "profiles".* FROM "profiles" WHERE "profiles"."usuario_id" = $1 ORDER BY "profiles"."id" ASC LIMIT 1 [["usuario_id", 12]]
CACHE (0.1ms) SELECT "usuarios".* FROM "usuarios" WHERE "usuarios"."id" = $1 ORDER BY "usuarios"."id" ASC LIMIT 1 [["id", 12]]
CACHE (0.0ms) SELECT "profiles".* FROM "profiles" WHERE "profiles"."usuario_id" = $1 ORDER BY "profiles"."id" ASC LIMIT 1 [["usuario_id", 12]]
CACHE (0.1ms) SELECT "usuarios".* FROM "usuarios" WHERE "usuarios"."id" = $1 ORDER BY "usuarios"."id" ASC LIMIT 1 [["id", 12]]
CACHE (0.1ms) SELECT "profiles".* FROM "profiles" WHERE "profiles"."usuario_id" = $1 ORDER BY "profiles"."id" ASC LIMIT 1 [["usuario_id", 12]]
CACHE (0.0ms) SELECT "usuarios".* FROM "usuarios" WHERE "usuarios"."id" = $1 ORDER BY "usuarios"."id" ASC LIMIT 1 [["id", 12]]
CACHE (0.0ms) SELECT "profiles".* FROM "profiles" WHERE "profiles"."usuario_id" = $1 ORDER BY "profiles"."id" ASC LIMIT 1 [["usuario_id", 12]]
CACHE (0.1ms) SELECT "usuarios".* FROM "usuarios" WHERE "usuarios"."id" = $1 ORDER BY "usuarios"."id" ASC LIMIT 1 [["id", 12]]
CACHE (0.1ms) SELECT "profiles".* FROM "profiles" WHERE "profiles"."usuario_id" = $1 ORDER BY "profiles"."id" ASC LIMIT 1 [["usuario_id", 12]]
Rendered usuarios/_user_texts.html.erb (16760.5ms)
Rendered usuarios/show.html.erb within layouts/application (28889.5ms)
Completed 200 OK in 29246ms (Views: 28898.8ms | ActiveRecord: 44.1ms)
As you can see, the views take ages to render.
This the "_user_texts" partial.
<div class="ui grid">
<% #textos.each do |texto| %>
<div class="text row" text-pages="<%= #textos.total_pages%>">
<div class="five wide column">
<%= image_tag texto.portada.url(:medium), :class => "ui rounded medium left floated image text-cover" %>
</div>
<div class="eleven wide column">
<div class="row">
<h1 class="ui header">
<%= link_to text_name(texto), usuario_texto_path(texto.usuario.id, texto.id), :class => "title-format"%>
<div class="sub header subheader-format">
escrito por <%= text_author_image texto %><%= text_author_name texto %> el <%= humanize_creation_date(texto.created_at) %>
</div>
</h1>
</div>
<div class="tag-list row">
<div class="ui horizontal list">
<% if not texto.tags.empty? %>
<% texto.tags.each do |tag| %>
<div class="tag item">
<%= link_to tag.nombre, tag_path(tag.id), :class => "ui red large label" %>
</div>
<% end %>
<% end %>
</div>
</div>
</div>
</div>
<% end %>
</div>
<% if #textos.total_pages > #textos.current_page %>
<a id="more_texts" href="javascript:void(0)">
<span class="vertical"></span><span>Ver más</span>
</a>
<% end %>
EDIT: I am using pagination. Specifically the will_paginate gem. When I get to the bottom of the page, there's a button for fetching more results.
Can somebody give me insights on how could I make it faster? This is driving me nuts.
Thanks!
I would benchmark your query, seems pretty heavy to me. I think the focus should be on enhancing the performance of your sql query. I have no knowledge of the exact content, but I doubt you need this much intelligence in a single query.
For instance, you could add indices within your table to improve performance. You should also consider what attributes you really need and use select to define them. Less columns in your query yield faster results.
Finally, you are doing a lot of joins. It seems like you are pretty much joining all of your models. Left joins are really slow, because you go over all records. If you really need all these joins, it would be great if you could turn some of those left joins to inner joins . This would mean a massive improvement, because you have to check only relevant records.
The query is not actually run until you call .all or .each in the view even if you store the results in an instance variable in the controller. This can make it seem like the views are slow when actually it's something in the database.
Try putting some calls to benchmark different places in your view to see where the time is being used.
http://api.rubyonrails.org/classes/ActiveSupport/Benchmarkable.html#method-i-benchmark
For seeing what you're query is doing and spotting missing indexes etc. explain is handy.
http://guides.rubyonrails.org/active_record_querying.html#running-explain
Solved. With the help of the Bullet gem, I reformulate the way I was eager loading.
It turns out that everything done was, in practice, well done. The issue was that my partner was storing the images for paperclip in Dropbox.
Dropbox is most likely not made for this kind of requests, so the delay was because of this. We will change to Amazon's S3.
For the reader from the future: be advised! And check where are you storing your images.
Thanks to everybody!
Related
I have 2 models: Deal and User with a many_to_many relations and a user_deal joined table.
On the homepage i display a list of Deals. For each Deal I use inside the view n attribute that is inside the user_deal table.
How can I eager load this ?
I tried to do this:
homepage controller
def home
#deals = Deal.includes(:user_deals)
respond_to do |format|
format.html # home.html.erb
format.json { render json: #deals }
format.xml { render xml: #deals }
# format.atom
end
end
end
Models
class Deal < ActiveRecord::Base
has_many :user_deals, dependent: :destroy
has_many :users, through: :user_deals
end
class User < ActiveRecord::Base
has_many :user_deals
has_many :deals, through: :user_deals
end
class UserDeal < ActiveRecord::Base
belongs_to :user, :foreign_key => 'user_id'
belongs_to :deal, :foreign_key => 'deal_id'
end
But I feel it's not working as it's preloading things but then loading each object a second time...
Processing by StaticPagesController#home as HTML
(0.5ms) SELECT COUNT(*) FROM "Deals" AND "Deals"."featured" = 't'
Deal Load (0.7ms)
SELECT "Deals".* FROM "Deals" WHERE "Deals"."country" = $1 AND "Deals"."featured" = 't' ORDER BY "Deals"."Deal_end_date" ASC
// it seems here below to implement the preloading
UserDeal Load (1.2ms) SELECT "user_deals".* FROM "user_Deals" WHERE "user_Deals"."Deal_id" IN (30, 339, 341, 337, 353, 31, 354, 260)
//but then it's loading things individually again
UserDeal Load (0.6ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 30) LIMIT 1
UserDeal Load (0.6ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 339) LIMIT 1
UserDeal Load (0.7ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 341) LIMIT 1
UserDeal Load (0.7ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 337) LIMIT 1
UserDeal Load (0.6ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 353) LIMIT 1
UserDeal Load (0.7ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 31) LIMIT 1
UserDeal Load (0.9ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 354) LIMIT 1
UserDeal Load (0.6ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 260) LIMIT 1
My assumption of where the problem comes from (I'm not sure)
The problem might be inside the User_deal table. It works this way: if a user participated in a deal, a new line is created with user_id = 5, deal_id= 4, number_of_participations = 6
So if the user 4 never participated in a deal 7, there is no line user_id= 4 and deal_id = 7
So on the homepage, Rails go to fetch the list of deals: deal 1, deal 2...and deal 7.
But he does not find the line where deal_7 as there is no such line.
Ideally, I should tell Rails to includes(:user_deals) but only those where inside the joined table UserDeals where user_id= current_user.id OR where the line with user_id = current_user.id does NOT exist...which I did not manager to implement anyway
but I'm a RoR rookie so I'm not sure of my ideas here above
EDIT
Following suggestion to try eager_load instead of includes, I get:
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["id", 625]]
Processing by StaticPagesController#home as HTML
(0.7ms) SELECT COUNT(DISTINCT "deals"."id") FROM "deals" LEFT OUTER JOIN "user_deals" ON "user_deals"."deal_id" = "deals"."id" WHERE "deals"."country" = $1 AND (deal_launch_date <= '2016-05-02 17:21:59.547029' AND deal_end_date >= '2016-05-02 17:21:59.547087') AND "deals"."featured" = 't' [["country", "France"]]
SQL (3.0ms) SELECT "deals"."id" AS t0_r0, "deals"."country" AS t0_r1, "deals"."title" AS t0_r2, "deals"."deal_card_edito" AS t0_r3, "deals"."twitter_msg" AS t0_r4, "deals"."image_url" AS t0_r5, "deals"."prelaunch_date" AS t0_r6, "deals"."featured" AS t0_r9, "deals"."admin_user_id" AS t0_r10, "deals"."created_at" AS t0_r11, "deals"."updated_at" AS t0_r12,........................................................................................................
"user_deals"."id" AS t1_r0, "user_deals"."user_id" AS t1_r1, "user_deals"."deal_id" AS t1_r2, "user_deals"."number_participations" AS t1_r3, "user_deals"."nb_new_clicks" AS t1_r4, "user_deals"."created_at" AS t1_r5, "user_deals"."updated_at" AS t1_r6 FROM "deals" LEFT OUTER JOIN "user_deals" ON "user_deals"."deal_id" = "deals"."id" WHERE "deals"."country" = $1 AND (deal_launch_date <= '2016-05-02 17:21:59.547029' AND deal_end_date >= '2016-05-02 17:21:59.547087') AND "deals"."featured" = 't' ORDER BY "deals"."deal_end_date" ASC [["country", "France"]]
UserDeal Load (0.9ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 30) LIMIT 1
UserDeal Load (1.0ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 339) LIMIT 1
UserDeal Load (0.6ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 341) LIMIT 1
UserDeal Load (0.6ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 337) LIMIT 1
UserDeal Load (0.9ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 353) LIMIT 1
UserDeal Load (1.0ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 31) LIMIT 1
UserDeal Load (0.5ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 354) LIMIT 1
UserDeal Load (0.9ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 260) LIMIT 1
I have a rails app where I often need to generate xls files with several values.
To do so I load customers orders in my controller (valid is just a custom scope)
#orders = Order.valid.order('id DESC')
In my view, I want to count meals for each orders with different scopes (i removed all xml tags, which are not interesting here):
<% #orders.each do |order| %>
<%= order.meals.count %>
<%= order.meals.meat.count %>
<%= order.meals.fish.count %>
<%= order.meals.drink.count %>
<%= order.meals.dessert.count %>
<% end %>
My problem is that this generates a very large number of SQL requests.
I tried to preload meals like this:
#orders = Order.valid.order('id DESC').preload(:meals)
But count requests keep being generated
I also found an old gem: preload_count to do this, but it doesn't works with rails 4.
Is there a way to optimize my requests ?
EDIT
After many tries and help from Andrey Deineko, my request turned into this:
Order.includes(:meals).valid.order('id DESC').references(:meals)
Then i realized it may come from meal types which are in another table in my DB
Order.eager_load(meals: :type).valid.order('orders.id DESC').references(:meals)
But still, here are my db requests:
(0.3ms) SELECT COUNT(*) FROM "meals" INNER JOIN "meals_orders" ON "meals"."id" = "meals_orders"."meal_id" WHERE "meals_orders"."order_id" = $1 [["order_id", 1044]]
(0.3ms) SELECT COUNT(*) FROM "meals" INNER JOIN "meals_orders" ON "meals"."id" = "meals_orders"."meal_id" WHERE "meals_orders"."order_id" = $1 [["order_id", 1044]]
(0.4ms) SELECT COUNT(*) FROM "meals" INNER JOIN "types" ON "types"."id" = "meals"."type_id" INNER JOIN "meals_orders" ON "meals"."id" = "meals_orders"."meal_id" WHERE "meals_orders"."order_id" = $1 AND "types"."name" = $2 [["order_id", 1044], ["name", "meat"]]
(0.4ms) SELECT COUNT(*) FROM "meals" INNER JOIN "types" ON "types"."id" = "meals"."type_id" INNER JOIN "meals_orders" ON "meals"."id" = "meals_orders"."meal_id" WHERE "meals_orders"."order_id" = $1 AND "types"."name" = $2 [["order_id", 1044], ["name", "meat"]]
(0.4ms) SELECT COUNT(*) FROM "meals" INNER JOIN "types" ON "types"."id" = "meals"."type_id" INNER JOIN "meals_orders" ON "meals"."id" = "meals_orders"."meal_id" WHERE "meals_orders"."order_id" = $1 AND "types"."name" = $2 [["order_id", 1044], ["name", "fish"]]
(0.4ms) SELECT COUNT(*) FROM "meals" INNER JOIN "types" ON "types"."id" = "meals"."type_id" INNER JOIN "meals_orders" ON "meals"."id" = "meals_orders"."meal_id" WHERE "meals_orders"."order_id" = $1 AND "types"."name" = $2 [["order_id", 1044], ["name", "fish"]]
(0.3ms) SELECT COUNT(*) FROM "meals" INNER JOIN "types" ON "types"."id" = "meals"."type_id" INNER JOIN "meals_orders" ON "meals"."id" = "meals_orders"."meal_id" WHERE "meals_orders"."order_id" = $1 AND "types"."name" = $2 [["order_id", 1044], ["name", "drink"]]
(0.3ms) SELECT COUNT(*) FROM "meals" INNER JOIN "types" ON "types"."id" = "meals"."type_id" INNER JOIN "meals_orders" ON "meals"."id" = "meals_orders"."meal_id" WHERE "meals_orders"."order_id" = $1 AND "types"."name" = $2 [["order_id", 1044], ["name", "drink"]]
(0.3ms) SELECT COUNT(*) FROM "meals" INNER JOIN "types" ON "types"."id" = "meals"."type_id" INNER JOIN "meals_orders" ON "meals"."id" = "meals_orders"."meal_id" WHERE "meals_orders"."order_id" = $1 AND "types"."name" = $2 [["order_id", 1044], ["name", "dessert"]]
go with
#orders = Order.includes(:meals).valid.order('id DESC')
if you want to have only orders with meals (no orders, where meal is nil) go with:
#orders = Order.joins(:meals).valid.order('id DESC')
Have a read about AR querying.
If your models have a has_many belongs_to relationship you can use includes to eager load the associations. This is a good article on eager loading.
I have two models: show_request and show. A show_Request belongs_to a show and a show has_many show_requests. On the show_request page in active_admin, I want to order show_requests by the show's created_at value. Here is my code so far:
ActiveAdmin.register ShowRequest do
controller do
def scoped_collection
end_of_association_chain.includes(:show)
#I also tried ShowRequest.includes(:show)
end
end
index do
column 'Show', sortable: "shows.created_at_asc" do |show_req|
link_to show_req.show.name, admin_show_path(show_req.show)
end
end
end
Here are the server logs:
Started GET "/admin/show_requests" for 127.0.0.1 at 2015-09-18 09:35:36 -0400
Processing by Admin::ShowRequestsController#index as HTML
AdminUser Load (0.3ms) SELECT "admin_users".* FROM "admin_users" WHERE "admin_users"."id" = 1 ORDER BY "admin_users"."id" ASC LIMIT 1
(1.2ms) SELECT COUNT(*) FROM "show_requests" WHERE (not_going_to_show = 'f' OR i_want_my_horse_to_compete = 't')
(0.2ms) SELECT COUNT(*) FROM "show_requests"
(0.2ms) SELECT COUNT(*) FROM "show_requests" WHERE (not_going_to_show = 't' AND i_want_my_horse_to_compete = 'f')
(0.3ms) SELECT COUNT(count_column) FROM (SELECT 1 AS count_column FROM "show_requests" WHERE (not_going_to_show = 'f' OR i_want_my_horse_to_compete = 't') LIMIT 30 OFFSET 0) subquery_for_count
CACHE (0.0ms) SELECT COUNT(count_column) FROM (SELECT 1 AS count_column FROM "show_requests" WHERE (not_going_to_show = 'f' OR i_want_my_horse_to_compete = 't') LIMIT 30 OFFSET 0) subquery_for_count
CACHE (0.0ms) SELECT COUNT(*) FROM "show_requests" WHERE (not_going_to_show = 'f' OR i_want_my_horse_to_compete = 't')
CACHE (0.0ms) SELECT COUNT(count_column) FROM (SELECT 1 AS count_column FROM "show_requests" WHERE (not_going_to_show = 'f' OR i_want_my_horse_to_compete = 't') LIMIT 30 OFFSET 0) subquery_for_count
ShowRequest Load (2.0ms) SELECT "show_requests".* FROM "show_requests" WHERE (not_going_to_show = 'f' OR i_want_my_horse_to_compete = 't') ORDER BY "show_requests"."id" desc LIMIT 30 OFFSET 0
Show Load (9.7ms) SELECT "shows".* FROM "shows" WHERE "shows"."id" IN (2, 1)
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 2]]
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 1]]
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 1]]
Show Load (0.2ms) SELECT "shows".* FROM "shows"
User Load (0.2ms) SELECT "users".* FROM "users"
This is not working. It is not affecting the order of the columns at all. How do I fix this?
Take a look at this part of the log:
ShowRequest Load (2.0ms) SELECT "show_requests".* FROM "show_requests" WHERE (not_going_to_show = 'f' OR i_want_my_horse_to_compete = 't') ORDER BY "show_requests"."id" desc LIMIT 30 OFFSET 0
Show Load (9.7ms) SELECT "shows".* FROM "shows" WHERE "shows"."id" IN (2, 1)
You can see that the ShowRequests and Shows are loaded in separate queries. sortable is not going to work here, because you can't order one table by a field of another without a join. The fix should be to tell ActiveRecord that you need to reference the shows table in your query:
controller do
def scoped_collection
super.includes(:show).references(:shows)
end
end
index do
column :show, sortable: 'shows.created_at'
end
references only works with includes, and forces Rails to perform a join when eager loading.
This is really nothing more than just looking for some explanation around why the joins clause is necessary for what I am doing. Both return everything I want properly, but the queries are different and one is less optimal:
TL;DR: What is Rails doing exactly when I combine the joins with the includes, I wouldn't have thought I needed the joins really. Thanks for anyone willing to actually read through this monster.
Note: object is a ToDoListsUser object, and this is all happening in an exporter for what it's worth. And ProgressItem is a joins table between User and ToDoItem.
With the joins clause (queries look good and as expected):
object.to_do_list.progress_items.where(user_id: object.user_id)
.joins(:to_do_item)
.includes(:to_do_item)
Server output:
ToDoListsUser Load (0.5ms) SELECT "to_do_lists_users".* FROM "to_do_lists_users" WHERE "to_do_lists_users"."user_id" = $1 ORDER BY "to_do_lists_users"."id" DESC OFFSET 0 [["user_id", 543]]
ToDoList Load (0.3ms) SELECT "to_do_lists".* FROM "to_do_lists" WHERE "to_do_lists"."id" = $1 LIMIT 1 [["id", 144]]
SQL (1.6ms) SELECT "progress_items"."id" AS t0_r0, "progress_items"."completed" AS t0_r1, "progress_items"."user_id" AS t0_r2, "progress_items"."to_do_item_id" AS t0_r3, "progress_items"."created_at" AS t0_r4, "progress_items"."updated_at" AS t0_r5, "progress_items"."hidden" AS t0_r6, "to_do_items_progress_items"."id" AS t1_r0, "to_do_items_progress_items"."to_do_list_id" AS t1_r1, "to_do_items_progress_items"."description" AS t1_r2, "to_do_items_progress_items"."date_due" AS t1_r3, "to_do_items_progress_items"."created_at" AS t1_r4, "to_do_items_progress_items"."updated_at" AS t1_r5, "to_do_items_progress_items"."name" AS t1_r6, "to_do_items_progress_items"."element_id" AS t1_r7, "to_do_items_progress_items"."linkable_id" AS t1_r8, "to_do_items_progress_items"."linkable_type" AS t1_r9, "to_do_items_progress_items"."action" AS t1_r10 FROM "progress_items" INNER JOIN "to_do_items" "to_do_items_progress_items" ON "to_do_items_progress_items"."id" = "progress_items"."to_do_item_id" INNER JOIN "to_do_items" ON "progress_items"."to_do_item_id" = "to_do_items"."id" WHERE "to_do_items"."to_do_list_id" = $1 AND "progress_items"."user_id" = $2 ORDER BY to_do_items.created_at [["to_do_list_id", 144], ["user_id", 543]]
ToDoList Load (0.4ms) SELECT "to_do_lists".* FROM "to_do_lists" WHERE "to_do_lists"."id" = $1 LIMIT 1 [["id", 133]]
SQL (3.3ms) SELECT "progress_items"."id" AS t0_r0, "progress_items"."completed" AS t0_r1, "progress_items"."user_id" AS t0_r2, "progress_items"."to_do_item_id" AS t0_r3, "progress_items"."created_at" AS t0_r4, "progress_items"."updated_at" AS t0_r5, "progress_items"."hidden" AS t0_r6, "to_do_items_progress_items"."id" AS t1_r0, "to_do_items_progress_items"."to_do_list_id" AS t1_r1, "to_do_items_progress_items"."description" AS t1_r2, "to_do_items_progress_items"."date_due" AS t1_r3, "to_do_items_progress_items"."created_at" AS t1_r4, "to_do_items_progress_items"."updated_at" AS t1_r5, "to_do_items_progress_items"."name" AS t1_r6, "to_do_items_progress_items"."element_id" AS t1_r7, "to_do_items_progress_items"."linkable_id" AS t1_r8, "to_do_items_progress_items"."linkable_type" AS t1_r9, "to_do_items_progress_items"."action" AS t1_r10 FROM "progress_items" INNER JOIN "to_do_items" "to_do_items_progress_items" ON "to_do_items_progress_items"."id" = "progress_items"."to_do_item_id" INNER JOIN "to_do_items" ON "progress_items"."to_do_item_id" = "to_do_items"."id" WHERE "to_do_items"."to_do_list_id" = $1 AND "progress_items"."user_id" = $2 ORDER BY to_do_items.created_at [["to_do_list_id", 133], ["user_id", 543]]
vs.
Without the joins clause (queries are not optimal):
object.to_do_list.progress_items.where(user_id: object.user_id)
.includes(:to_do_item)
Server output:
ToDoListsUser Load (0.3ms) SELECT "to_do_lists_users".* FROM "to_do_lists_users" WHERE "to_do_lists_users"."user_id" = $1 ORDER BY "to_do_lists_users"."id" DESC OFFSET 0 [["user_id", 543]]
ToDoList Load (0.4ms) SELECT "to_do_lists".* FROM "to_do_lists" WHERE "to_do_lists"."id" = $1 LIMIT 1 [["id", 144]]
ProgressItem Load (2.0ms) SELECT "progress_items".* FROM "progress_items" INNER JOIN "to_do_items" ON "progress_items"."to_do_item_id" = "to_do_items"."id" WHERE "to_do_items"."to_do_list_id" = $1 AND "progress_items"."user_id" = $2 ORDER BY to_do_items.created_at [["to_do_list_id", 144], ["user_id", 543]]
ToDoList Load (0.5ms) SELECT "to_do_lists".* FROM "to_do_lists" WHERE "to_do_lists"."id" = $1 LIMIT 1 [["id", 133]]
ProgressItem Load (0.5ms) SELECT "progress_items".* FROM "progress_items" INNER JOIN "to_do_items" ON "progress_items"."to_do_item_id" = "to_do_items"."id" WHERE "to_do_items"."to_do_list_id" = $1 AND "progress_items"."user_id" = $2 ORDER BY to_do_items.created_at [["to_do_list_id", 133], ["user_id", 543]]
ToDoItem Load (0.4ms) SELECT "to_do_items".* FROM "to_do_items" WHERE "to_do_items"."id" IN (193, 194, 195, 196)
From ActiveRecord documentation:
conditions
If you want to add conditions to your included models you’ll have to explicitly reference them. For example:
User.includes(:posts).where('posts.name = ?', 'example')
Will throw an error, but this will work:
User.includes(:posts).where('posts.name = ?', 'example').references(:posts)
Note that includes works with association names while references needs the actual table name.
That happens, because actually Rails with include doesn't do join, it fetches records with two requests.
For example:
class List < ActiveRecord::Base
has_many :tasks
end
List.includes(:tasks)
# List Load (1.9ms) SELECT "lists".* FROM "lists"
# Task Load (0.8ms) SELECT "tasks".* FROM "tasks" WHERE "tasks"."list_id" IN (1, 2, 3)
But with references it falls back to join:
List.includes(:tasks).references(:tasks)
# SQL (0.6ms) SELECT "lists"."id" AS t0_r0, "lists"."name" AS t0_r1,
# "tasks"."id" AS t1_r0, "tasks"."name" AS t1_r1 FROM
# "lists" LEFT OUTER JOIN "tasks" ON "tasks"."list_id" = "lists"."id"
I was given a legacy spree app and I am supposed to edit one of the deeper checkout pages, but I can't get to it on my local because it keeps redirecting me to the shopping cart page with the flash:
Can't check out, no payment methods are configured for this environment
My database should be identical to the production database. I can't find Can't check out, no payment methods are configured for this environment anywhere in the project. How would I get past this?
I checked the log and it looks like there's a before_filter that's preventing me from going through: Filter chain halted as [:ensure_payment_methods] rendered_or_redirected.. However, I can't find this method anywhere in the code. How do I edit controllers that don't exist in my project? How do I find out where they are?
Here's my log:
Processing CheckoutsController#edit (for 127.0.0.1 at 2013-09-20 10:26:15) [GET]
Parameters: {"action"=>"edit", "controller"=>"checkouts", "order_id"=>"R838445544"}
Cache hit: Spree::Config ({})
Cache hit: Spree::Config ({})
Order Load (0.6ms) SELECT * FROM "orders" WHERE ("orders"."number" = 'R838445544') LIMIT 1
Cache hit: Spree::Config ({})
Zone Load (0.3ms) SELECT * FROM "zones" WHERE ("zones"."name" IS NULL) LIMIT 1
Country Load (0.8ms) SELECT * FROM "countries"
CACHE (0.0ms) SELECT * FROM "orders" WHERE ("orders"."number" = 'R838445544') LIMIT 1
Checkout Load (0.7ms) SELECT * FROM "checkouts" WHERE ("checkouts".order_id = 4744) LIMIT 1
CACHE (0.0ms) SELECT * FROM "orders" WHERE ("orders"."number" = 'R838445544') LIMIT 1
Cache hit: Spree::Config ({})
Country Load (0.2ms) SELECT * FROM "countries" WHERE ("countries"."id" = 214)
Cache hit: Spree::Config ({})
CACHE (0.0ms) SELECT * FROM "countries" WHERE ("countries"."id" = 214)
State Load (0.4ms) SELECT * FROM "states" WHERE ("states".country_id = 214)
CACHE (0.0ms) SELECT * FROM "orders" WHERE ("orders"."number" = 'R838445544') LIMIT 1
Cache hit: Spree::Config ({})
Cache hit: Spree::Config ({})
CACHE (0.0ms) SELECT * FROM "orders" WHERE ("orders"."number" = 'R838445544') LIMIT 1
Redirected to http://localhost:3000/boutique/orders/R838445544/checkout/register
Filter chain halted as [:enforce_registration] rendered_or_redirected.
Completed in 77ms (DB: 5) | 302 Found [http://localhost/boutique/orders/R838445544/checkout/edit]
Property Load (0.3ms) SELECT * FROM "properties" WHERE ("properties"."name" = 'brand') LIMIT 1
AppConfiguration Load (0.4ms) SELECT * FROM "configurations" WHERE ("configurations"."name" = 'Default configuration') AND ( ("configurations"."type" = 'AppConfiguration' ) ) LIMIT 1
Cache hit: Spree::Config ({})
requiring dependency
finished requiring.
SQL (0.1ms) SET client_min_messages TO 'panic'
SQL (0.1ms) SET standard_conforming_strings = on
SQL (0.1ms) SET client_min_messages TO 'notice'
User Load IDs For Limited Eager Loading (1.3ms) SELECT DISTINCT "users".id FROM "users" LEFT OUTER JOIN "roles_users" ON "roles_users".user_id = "users".id LEFT OUTER JOIN "roles" ON "roles".id = "roles_users".role_id WHERE (roles.name = 'admin') LIMIT 1
User Load Including Associations (0.8ms) SELECT "users"."id" AS t0_r0, "users"."email" AS t0_r1, "users"."crypted_password" AS t0_r2, "users"."salt" AS t0_r3, "users"."remember_token" AS t0_r4, "users"."remember_token_expires_at" AS t0_r5, "users"."created_at" AS t0_r6, "users"."updated_at" AS t0_r7, "users"."persistence_token" AS t0_r8, "users"."single_access_token" AS t0_r9, "users"."perishable_token" AS t0_r10, "users"."login_count" AS t0_r11, "users"."failed_login_count" AS t0_r12, "users"."last_request_at" AS t0_r13, "users"."current_login_at" AS t0_r14, "users"."last_login_at" AS t0_r15, "users"."current_login_ip" AS t0_r16, "users"."last_login_ip" AS t0_r17, "users"."login" AS t0_r18, "users"."ship_address_id" AS t0_r19, "users"."bill_address_id" AS t0_r20, "users"."openid_identifier" AS t0_r21, "users"."api_key" AS t0_r22, "users"."creditcard_id" AS t0_r23, "roles"."id" AS t1_r0, "roles"."name" AS t1_r1 FROM "users" LEFT OUTER JOIN "roles_users" ON "roles_users".user_id = "users".id LEFT OUTER JOIN "roles" ON "roles".id = "roles_users".role_id WHERE (roles.name = 'admin') AND "users".id IN (1)
Processing CheckoutsController#register (for 127.0.0.1 at 2013-09-20 10:26:17) [GET]
Parameters: {"action"=>"register", "controller"=>"checkouts", "order_id"=>"R838445544"}
Cache hit: Spree::Config ({})
Cache hit: Spree::Config ({})
Order Load (0.5ms) SELECT * FROM "orders" WHERE ("orders"."number" = 'R838445544') LIMIT 1
Cache hit: Spree::Config ({})
Zone Load (0.2ms) SELECT * FROM "zones" WHERE ("zones"."name" IS NULL) LIMIT 1
Country Load (0.7ms) SELECT * FROM "countries"
CACHE (0.0ms) SELECT * FROM "orders" WHERE ("orders"."number" = 'R838445544') LIMIT 1
Checkout Load (0.6ms) SELECT * FROM "checkouts" WHERE ("checkouts".order_id = 4744) LIMIT 1
CACHE (0.0ms) SELECT * FROM "orders" WHERE ("orders"."number" = 'R838445544') LIMIT 1
Cache hit: Spree::Config ({})
Country Load (0.2ms) SELECT * FROM "countries" WHERE ("countries"."id" = 214)
Cache hit: Spree::Config ({})
CACHE (0.0ms) SELECT * FROM "countries" WHERE ("countries"."id" = 214)
State Load (0.4ms) SELECT * FROM "states" WHERE ("states".country_id = 214)
CACHE (0.0ms) SELECT * FROM "orders" WHERE ("orders"."number" = 'R838445544') LIMIT 1
PaymentMethod Load (0.4ms) SELECT * FROM "payment_methods" WHERE ("payment_methods"."deleted_at" IS NULL)
Redirected to http://localhost:3000/boutique/orders/R838445544/edit
Filter chain halted as [:ensure_payment_methods] rendered_or_redirected.
Completed in 83ms (DB: 5) | 302 Found [http://localhost/boutique/orders/R838445544/checkout/register]
Property Load (0.3ms) SELECT * FROM "properties" WHERE ("properties"."name" = 'brand') LIMIT 1
AppConfiguration Load (0.3ms) SELECT * FROM "configurations" WHERE ("configurations"."name" = 'Default configuration') AND ( ("configurations"."type" = 'AppConfiguration' ) ) LIMIT 1
Cache hit: Spree::Config ({})
requiring dependency
finished requiring.
SQL (0.1ms) SET client_min_messages TO 'panic'
SQL (0.1ms) SET standard_conforming_strings = on
SQL (0.1ms) SET client_min_messages TO 'notice'
User Load IDs For Limited Eager Loading (1.3ms) SELECT DISTINCT "users".id FROM "users" LEFT OUTER JOIN "roles_users" ON "roles_users".user_id = "users".id LEFT OUTER JOIN "roles" ON "roles".id = "roles_users".role_id WHERE (roles.name = 'admin') LIMIT 1
User Load Including Associations (0.8ms) SELECT "users"."id" AS t0_r0, "users"."email" AS t0_r1, "users"."crypted_password" AS t0_r2, "users"."salt" AS t0_r3, "users"."remember_token" AS t0_r4, "users"."remember_token_expires_at" AS t0_r5, "users"."created_at" AS t0_r6, "users"."updated_at" AS t0_r7, "users"."persistence_token" AS t0_r8, "users"."single_access_token" AS t0_r9, "users"."perishable_token" AS t0_r10, "users"."login_count" AS t0_r11, "users"."failed_login_count" AS t0_r12, "users"."last_request_at" AS t0_r13, "users"."current_login_at" AS t0_r14, "users"."last_login_at" AS t0_r15, "users"."current_login_ip" AS t0_r16, "users"."last_login_ip" AS t0_r17, "users"."login" AS t0_r18, "users"."ship_address_id" AS t0_r19, "users"."bill_address_id" AS t0_r20, "users"."openid_identifier" AS t0_r21, "users"."api_key" AS t0_r22, "users"."creditcard_id" AS t0_r23, "roles"."id" AS t1_r0, "roles"."name" AS t1_r1 FROM "users" LEFT OUTER JOIN "roles_users" ON "roles_users".user_id = "users".id LEFT OUTER JOIN "roles" ON "roles".id = "roles_users".role_id WHERE (roles.name = 'admin') AND "users".id IN (1)
Processing OrdersController#edit (for 127.0.0.1 at 2013-09-20 10:26:19) [GET]
Parameters: {"action"=>"edit", "controller"=>"orders", "id"=>"R838445544"}
Order Load (0.5ms) SELECT * FROM "orders" WHERE ("orders"."number" = 'R838445544') LIMIT 1
Adjustment Load (0.4ms) SELECT "adjustments".* FROM "adjustments" WHERE ("adjustments".order_id = 4744) ORDER BY position
Cache hit: Spree::Config ({})
Checkout Load (0.6ms) SELECT * FROM "checkouts" WHERE ("checkouts".order_id = 4744) LIMIT 1
SQL (0.1ms) BEGIN
Order Load (0.2ms) SELECT * FROM "orders" WHERE ("orders"."id" = 4744)
Shipment Load (1.8ms) SELECT * FROM "shipments" WHERE ("shipments".order_id = 4744) ORDER BY shipments.id DESC LIMIT 1
CACHE (0.0ms) SELECT * FROM "orders" WHERE ("orders"."id" = 4744)
SQL (0.1ms) COMMIT
SQL (0.1ms) BEGIN
LineItem Load (0.4ms) SELECT * FROM "line_items" WHERE ("line_items".order_id = 4744)
Variant Load (0.5ms) SELECT * FROM "variants" WHERE ("variants"."id" = 179)
CACHE (0.0ms) SELECT * FROM "orders" WHERE ("orders"."id" = 4744)
Cache hit: Spree::Config ({})
Cache hit: Spree::Config ({})
InventoryUnit Load (0.5ms) SELECT * FROM "inventory_units" WHERE (inventory_units.order_id = 4744) LIMIT 1
Cache hit: Spree::Config ({})
Shipment Load (1.0ms) SELECT * FROM "shipments" WHERE ("shipments".order_id = 4744)
Charge Load (0.3ms) SELECT * FROM "adjustments" WHERE ("adjustments".order_id = 4744) AND ( ("adjustments"."type" = 'Charge' OR "adjustments"."type" = 'TaxCharge' OR "adjustments"."type" = 'ShippingCharge' ) ) ORDER BY position
CACHE (0.0ms) SELECT * FROM "orders" WHERE ("orders"."id" = 4744)
CACHE (0.0ms) SELECT * FROM "orders" WHERE ("orders"."id" = 4744)
CACHE (0.0ms) SELECT * FROM "shipments" WHERE ("shipments".order_id = 4744) ORDER BY shipments.id DESC LIMIT 1
Cache hit: Spree::Config ({})
Credit Load (0.2ms) SELECT * FROM "adjustments" WHERE ("adjustments".order_id = 4744) AND ( ("adjustments"."type" = 'Credit' OR "adjustments"."type" = 'GiftCardCredit' OR "adjustments"."type" = 'CouponCredit' OR "adjustments"."type" = 'ManagersDiscountCredit' OR "adjustments"."type" = 'ReturnAuthorizationCredit' ) ) ORDER BY position
SQL (0.1ms) COMMIT
Rendering template within layouts/spree_application
Rendering orders/edit
Image Load (0.6ms) SELECT * FROM "assets" WHERE ("assets".viewable_id = 179 AND "assets".viewable_type = 'Variant') AND ( ("assets"."type" = 'Image' OR "assets"."type" = 'ProductThumbnail' OR "assets"."type" = 'ProductPageImage' ) ) ORDER BY position
Product Load (0.7ms) SELECT * FROM "products" WHERE ("products"."id" = 85)
SQL (0.5ms) SELECT count(*) AS count_all FROM "assets" WHERE ("assets".viewable_id = 85 AND "assets".viewable_type = 'Product') AND ( ("assets"."type" = 'Image' OR "assets"."type" = 'ProductThumbnail' OR "assets"."type" = 'ProductPageImage' ) )
Image Load (0.3ms) SELECT * FROM "assets" WHERE ("assets".viewable_id = 85 AND "assets".viewable_type = 'Product') AND ( ("assets"."type" = 'Image' OR "assets"."type" = 'ProductThumbnail' OR "assets"."type" = 'ProductPageImage' ) ) ORDER BY position LIMIT 1
Cache hit: Spree::Config ({})
OptionValue Load (0.7ms) SELECT * FROM "option_values" INNER JOIN "option_values_variants" ON "option_values".id = "option_values_variants".option_value_id WHERE ("option_values_variants".variant_id = 179 )
OptionType Load (0.3ms) SELECT * FROM "option_types" WHERE ("option_types"."id" = 1)
Cache hit: Spree::Config ({})
Cache hit: Spree::Config ({})
Cache hit: Spree::Config ({})
Cache hit: Spree::Config ({})
Cache hit: Spree::Config ({})
Cache hit: Spree::Config ({})
Cache hit: Spree::Config ({})
Cache hit: Spree::Config ({})
Rendered orders/_line_item (195.9ms)
Cache hit: Spree::Config ({})
Cache hit: Spree::Config ({})
Rendered orders/_form (201.2ms)
Rendered orders/_delivery (0.9ms)
Taxonomy Load (0.6ms) SELECT * FROM "taxonomies" WHERE (name != 'Featured Products') ORDER BY id
Taxon Load (0.7ms) SELECT "taxons".* FROM "taxons" WHERE ("taxons".taxonomy_id IN (1,5,6,7,8) AND (parent_id is null))
Taxon Load (0.3ms) SELECT "taxons".* FROM "taxons" WHERE ("taxons".parent_id IN (1,33,34,35,37)) ORDER BY "lft"
Rendered shared/_taxonomies (25.5ms)
Cache hit: Spree::Config ({})
Rendered shared/_head (2.7ms)
Rendered shared/_store_menu (0.7ms)
Order Load (0.3ms) SELECT * FROM "orders" WHERE ("orders"."id" = 4744) LIMIT 1
CACHE (0.0ms) SELECT * FROM "orders" WHERE ("orders"."id" = 4744) LIMIT 1
CACHE (0.0ms) SELECT * FROM "line_items" WHERE ("line_items".order_id = 4744)
Rendered shared/_nav_bar (3.5ms)
Taxon Load (0.2ms) SELECT * FROM "taxons" WHERE ("taxons"."permalink" = 'caviar/') LIMIT 1
**#selected_tab is nil
Tracker Load (0.4ms) SELECT * FROM "trackers" WHERE ("trackers"."active" = 't' AND "trackers"."environment" = 'development') LIMIT 1
Rendered shared/_google_analytics (14.7ms)
Rendered shared/_footer (23.6ms)
Completed in 400ms (View: 295, DB: 15) | 200 OK [http://localhost/boutique/orders/R838445544/edit]
Property Load (0.3ms) SELECT * FROM "properties" WHERE ("properties"."name" = 'brand') LIMIT 1
AppConfiguration Load (0.4ms) SELECT * FROM "configurations" WHERE ("configurations"."name" = 'Default configuration') AND ( ("configurations"."type" = 'AppConfiguration' ) ) LIMIT 1
Cache hit: Spree::Config ({})
requiring dependency
finished requiring.
If you look at your spree_payment_methods table you will see a column called environment. Most likely you don't have any rows with the value of 'development' in you environment column.
Navigate to /admin
click configuration
in the right side list click on payment methods
Create a payment method and that should solve your problem.
In general you want to clone a local copy of Spree or whatever Spree expansions you have in your Gemfile, and grep on that to find what you need.