How to sort :order nil? - ruby-on-rails

Basically everytime a page loads this error pops up in the terminal. It doesn't seem to be causing any tangible issues:
NoMethodError (undefined method `each' for nil:NilClass): app/controllers/habits_controller.rb:8:in `sort'
I want to fix it though and I have a general idea how to.
When a new habit is created instead of its :order defaulting to nil it should default to the next highest integer.
HabitsController
def sort
params[:order].each do |id, order|
Habit.where(id: id).update_all(order: order)
end
render nothing: true
end
def habit_params
params.require(:habit).permit(
:user_id,
:trigger,
:tag_list,
:current_level,
:conceal,
:missed_days,
:target,
:reward,
:comment,
:commentable,
:like,
:likeable,
:action,
:order,
:date_started,
:missed_one,
:completed,
:completed_at,
:notes_text,
:notes_date,
:notable,
:note,
:committed => [],
levels_attributes: [
:missed_days,
:days_lost], notes_attributes: [:notable, :note, :notes_text, :notes_date, :_destroy])
end
schema
create_table "habits", force: true do |t|
t.integer "order"
end
rails c
[2] pry(main)> Habit.last
Habit Load (2.9ms) SELECT "habits".* FROM "habits" ORDER BY "habits"."id" DESC LIMIT 1
=> #<Habit:0x007f94e0da39b0
id: 12,
missed_days: 0,
conceal: false,
likes: nil,
date_started: Tue, 15 Sep 2015 00:00:00 EDT -04:00,
trigger: "wake up",
action: "run",
target: "2 miles",
reward: "eat dessert",
user_id: 2,
created_at: Tue, 15 Sep 2015 09:53:31 EDT -04:00,
updated_at: Tue, 15 Sep 2015 09:53:31 EDT -04:00,
order: nil,
completed_at: nil,
committed: ["sun", "mon", "tue", "wed", "thu", "fri", "sat", ""],
strike_date: nil,
missed_days_date: nil>
rails s
Started POST "/habits/sort" for 127.0.0.1 at 2015-09-15 10:02:36 -0400
Processing by HabitsController#sort as */*
User Load (2.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 2]]
Habit Load (0.4ms) SELECT "habits".* FROM "habits" WHERE "habits"."user_id" = $1 [["user_id", 2]]
ActsAsTaggableOn::Tag Load (0.5ms) SELECT "tags".* FROM "tags" WHERE (LOWER(name) = LOWER('ingrain'))
CACHE (0.0ms) SELECT "habits".* FROM "habits" WHERE "habits"."user_id" = $1 [["user_id", 2]]
Level Load (0.3ms) SELECT "levels".* FROM "levels" WHERE "levels"."habit_id" = $1 ORDER BY "levels"."id" ASC [["habit_id", 11]]
Level Load (0.3ms) SELECT "levels".* FROM "levels" WHERE "levels"."habit_id" = $1 ORDER BY "levels"."id" ASC [["habit_id", 12]]
Level Load (0.3ms) SELECT "levels".* FROM "levels" WHERE "levels"."habit_id" = $1 ORDER BY "levels"."id" ASC [["habit_id", 10]]
ActsAsTaggableOn::Tag Load (0.3ms) SELECT DISTINCT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."tagger_id" = $1 AND "taggings"."tagger_type" = $2 ORDER BY taggings_count desc LIMIT 20 [["tagger_id", 2], ["tagger_type", "User"]]
(0.3ms) SELECT COUNT(*) FROM "habits" WHERE "habits"."user_id" = $1 [["user_id", 2]]
Completed 500 Internal Server Error in 51ms
NoMethodError (undefined method `each' for nil:NilClass): app/controllers/habits_controller.rb:8:in `sort'
habit-sort.js
var update_orders, update_remote_orders;
update_remote_orders = function(orders) {
return $.ajax({
url: "/habits/sort",
type: "POST",
data: {
order: orders
},
success: function(data) {}
});
};
update_orders = function() {
var orders;
orders = {};
$("#sortable tr input.order:hidden").each(function(i, o) {
orders[$(o).attr("data-id")] = i;
return $(o).val(i);
});
return update_remote_orders(orders);
};
$(document).ready(function() {
update_orders();
$("#sortable").sortable({
axis: 'y',
handle: ".btn",
stop: function(ui, event) {
return update_orders();
}
});
});

Related

rails4 - malformed format string

After the correction of a wrong syntax I have a new error and I am not sure where it comes from:
categories were created in the console
Category Load (2.0ms) SELECT "categories".* FROM "categories"
=> #<ActiveRecord::Relation [#<Category id: 1, name: "Ruby", created_at: "2016-09-26 09:03:17", updated_at: "2016-09-26 09:03:17">, #<Category id: 2, name: "Rails4", created_at: "2016-09-26 09:03:25", updated_at: "2016-09-27 14:32:39">, #<Category id: 3, name: "Rails5", created_at: "2016-09-26 09:03:30", updated_at: "2016-09-27 14:35:25">, #<Category id: 4, name: "Heroku", created_at: "2016-09-26 09:03:35", updated_at: "2016-09-27 14:35:47">, #<Category id: 5, name: "AWS-Amazon", created_at: "2016-09-26 09:03:43", updated_at: "2016-09-26 09:03:43">]>
When I select:
"Ruby" I have: malformed format string - %R
"Rails4" I have: malformed format string - %R
"Rails5" I have: malformed format string - %R
"Heroku" I have: malformed format string - %H
"AWS-Amazon" I have: too few arguments
I am trying to filter my categories by name:
category model
class Category < ActiveRecord::Base
has_many :tutos
def self.filter(filter)
if filter
where(["name LIKE '%#{filter}%'"]).order('created_at DESC')
else
all
end
end
end
1st Edit
I've tried different way but I have issues in each:
`where(["name LIKE '%#{filter}%'"]).order('created_at DESC')`
returns the malformed string alert
`where("name LIKE '%#{filter}%'").order(created_at: :desc)`
and
`where("name LIKE ?", "%#{filter}%").order('created_at DESC')`
return all the categories without filtering....
you may want to see the tutos/views/index
.container
.row
h1.text-gray Tutorials
.row.search_banner
.col-xs-3
=form_tag tutos_path, :method => 'get' do
=text_field_tag :search, params[:search], placeholder:"Search by keywords"
=submit_tag "Search", class:'btn btn-xs btn-default btn-search'
.col-xs-3
=form_tag tutos_path, :method => 'get' do
=select_tag :filter, options_for_select(Category.all.map{|c| c.name}, params[:filter])
=submit_tag "Search", class:"btn btn-xs btn-default btn-search"
.col-xs-3
-if user_signed_in?
= link_to "Create a tuto", new_tuto_path, class:"btn btn-success"
br
br
#tutos.transitions-enabled
-#tutos.each do |tuto|
.box.panel-default
= link_to image_tag(image_by_category(tuto.category.try(:name))), tuto_path(tuto)
h3 = link_to tuto.title, tuto_path(tuto), class:"title-link"
h6
| Created by:
span<>
= tuto.user.full_name
br
span.glyphicon.glyphicon-heart
span<>
= tuto.get_upvotes.size
br
br
2nd edit
Rails console log : if I search for "Heroku" Cartegory:
but as my categories belongs to tutos... (Maybe have a look on the website filter are not online yet though but you will see the idea)
Should I do something like this
Tuto.category.where("name LIKE ?", "%#{filter}%").order('created_at DESC')
Started GET "/tutos?utf8=%E2%9C%93&filter=Heroku&commit=Search" for ::1 at 2016-09-28 17:50:41 +0200
Processing by TutosController#index as HTML
Parameters: {"utf8"=>"✓", "filter"=>"Heroku", "commit"=>"Search"}
Category Load (0.3ms) SELECT "categories".* FROM "categories"
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1 [["id", 1]]
Tuto Load (0.1ms) SELECT "tutos".* FROM "tutos"
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" IN (1)
Category Load (0.1ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" IN (2, 3, 5, 4, 1)
(0.1ms) SELECT COUNT(*) FROM "votes" WHERE "votes"."votable_id" = ? AND "votes"."votable_type" = ? AND "votes"."vote_flag" = ? AND "votes"."vote_scope" IS NULL [["votable_id", 16], ["votable_type", "Tuto"], ["vote_flag", "t"]]
(0.1ms) SELECT COUNT(*) FROM "votes" WHERE "votes"."votable_id" = ? AND "votes"."votable_type" = ? AND "votes"."vote_flag" = ? AND "votes"."vote_scope" IS NULL [["votable_id", 17], ["votable_type", "Tuto"], ["vote_flag", "t"]]
(0.0ms) SELECT COUNT(*) FROM "votes" WHERE "votes"."votable_id" = ? AND "votes"."votable_type" = ? AND "votes"."vote_flag" = ? AND "votes"."vote_scope" IS NULL [["votable_id", 18], ["votable_type", "Tuto"], ["vote_flag", "t"]]
(0.0ms) SELECT COUNT(*) FROM "votes" WHERE "votes"."votable_id" = ? AND "votes"."votable_type" = ? AND "votes"."vote_flag" = ? AND "votes"."vote_scope" IS NULL [["votable_id", 19], ["votable_type", "Tuto"], ["vote_flag", "t"]]
(0.0ms) SELECT COUNT(*) FROM "votes" WHERE "votes"."votable_id" = ? AND "votes"."votable_type" = ? AND "votes"."vote_flag" = ? AND "votes"."vote_scope" IS NULL [["votable_id", 20], ["votable_type", "Tuto"], ["vote_flag", "t"]]
(0.0ms) SELECT COUNT(*) FROM "votes" WHERE "votes"."votable_id" = ? AND "votes"."votable_type" = ? AND "votes"."vote_flag" = ? AND "votes"."vote_scope" IS NULL [["votable_id", 21], ["votable_type", "Tuto"], ["vote_flag", "t"]]
(0.0ms) SELECT COUNT(*) FROM "votes" WHERE "votes"."votable_id" = ? AND "votes"."votable_type" = ? AND "votes"."vote_flag" = ? AND "votes"."vote_scope" IS NULL [["votable_id", 22], ["votable_type", "Tuto"], ["vote_flag", "t"]]
(0.0ms) SELECT COUNT(*) FROM "votes" WHERE "votes"."votable_id" = ? AND "votes"."votable_type" = ? AND "votes"."vote_flag" = ? AND "votes"."vote_scope" IS NULL [["votable_id", 23], ["votable_type", "Tuto"], ["vote_flag", "t"]]
(0.0ms) SELECT COUNT(*) FROM "votes" WHERE "votes"."votable_id" = ? AND "votes"."votable_type" = ? AND "votes"."vote_flag" = ? AND "votes"."vote_scope" IS NULL [["votable_id", 24], ["votable_type", "Tuto"], ["vote_flag", "t"]]
Rendered tutos/index.html.slim within layouts/application (29.0ms)
Rendered layouts/_nav.html.slim (0.4ms)
Completed 200 OK in 104ms (Views: 94.1ms | ActiveRecord: 1.9ms)
3rd Edit
tuto model
class Tuto < ActiveRecord::Base
acts_as_votable
belongs_to :user
belongs_to :category
validates :category_id, presence: true
def self.search(search)
if search
where(["title LIKE ?","%#{search}%"]).order('created_at DESC')
else
all
end
end
end
category model
I've build my category filter like the tuto search
class Category < ActiveRecord::Base
has_many :tutos
def self.filter(filter)
if filter
#where(["name LIKE '%#{filter}%'"]).order('created_at DESC')
#where("name LIKE '%#{filter}%'").order(created_at: :desc)
where("name LIKE ?", "%#{filter}%").order('created_at DESC')
else
all
end
end
end
Checked with the suggested raise 'check'
Feel free to ask for more code if needed, as I am not sure where I am wrong...
Many thanks
regards
I fixed it !
In my controller tutos I did this:
many thanks to fanta who took me on the right way !
def index
#binding.pry
if params[:search].present?
#tutos = Tuto.search(params[:search]).includes(:user, :category)
else
#tutos = Tuto.all.includes(:user, :category)
end
if params[:filter].present?
#tutos = Tuto.joins(:category).where('categories.name LIKE ?', params[:filter])
else
#categories = Category.all
end
end
where("name LIKE ?", "%#{filter}%").order('created_at DESC')

Can't get the value stored when updating attributes

I am trying to do a marking system for moderators, in which they can select each item as "editor pick".
I've added a :editor_pick column to photos table(boolean)
and added a form in the partial for each item to have a checkbox in it:
<% if controller_name == "photos" %>
<%= simple_form_for [#user, #photo] do |f| %>
<%= f.input :editor_pick, label: "Portada" %>
<%= f.submit "Pick" %>
<% end %>
<% end %>
after that, I required the new param in strong parameters in photos controller
It's redirecting me correctly after the update, but it's not saving the new value.
When I reload the page, the boolean is still false.
My controller actions:
def by_zone
#photo = Photo.find_by(params[:id])
#user = #photo.user
render :index
end
def update
#photo = Photo.friendly.find(params[:id])
if #photo.update_attributes(photo_params)
redirect_to [current_user, #photo], notice: 'El spot se ha actualizado.'
else
render 'edit'
end
end
Edit
def photo_params
params.require(:photo).permit(:editor_pick,:url,:remote_photo_url,:thumbnail_cache ,:order,:string_tags,:tag_list, :sponsored, :photo, :terms, :title,:description,:category_id,:zone_id, :crop_x, :crop_y, :crop_w, :crop_h, sponsors_attributes: [:name, :description, :web, :facebook, :twitter, :sponsored_avatar])
end
Params Edit
Started PATCH "/users/enrique-isasi-12/photos/rustic-plastic-table" for 127.0.0.1 at 2015-01-14 16:43:55 +0100
Processing by PhotosController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"wB2SmOT0zR0dwIIguRhzFdctY51LX333CzGYelxS4Hs=", "photo"=>{"editor_pick"=>"1"}, "commit"=>"Pick", "user_id"=>"enrique-isasi-12", "id"=>"rustic-plastic-table"}
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = 5 ORDER BY "users"."id" ASC LIMIT 1
Notification Load (0.3ms) SELECT "notifications".* FROM "notifications" WHERE "notifications"."user_id" = $1 AND "notifications"."viewed_at" IS NULL ORDER BY "notifications"."created_at" DESC LIMIT 30 [["user_id", 5]]
Notification Load (0.2ms) SELECT "notifications".* FROM "notifications" WHERE "notifications"."user_id" = $1 AND (viewed_at IS NOT NULL) ORDER BY "notifications"."created_at" DESC LIMIT 30 [["user_id", 5]]
Photo Load (0.4ms) SELECT "photos".* FROM "photos" WHERE "photos"."slug" = 'rustic-plastic-table' ORDER BY "photos"."id" ASC LIMIT 1
(0.4ms) BEGIN
Category Load (0.3ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = $1 ORDER BY "categories"."id" ASC LIMIT 1 [["id", 2]]
Zone Load (0.3ms) SELECT "zones".* FROM "zones" WHERE "zones"."id" = $1 ORDER BY "zones"."id" ASC LIMIT 1 [["id", 6]]
ActsAsTaggableOn::Tag Load (0.2ms) SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."taggable_id" = $1 AND "taggings"."taggable_type" = $2 AND (taggings.context = 'tags' AND taggings.tagger_id IS NULL) [["taggable_id", 26], ["taggable_type", "Photo"]]
SQL (0.6ms) UPDATE "photos" SET "editor_pick" = $1, "updated_at" = $2 WHERE "photos"."id" = 26 [["editor_pick", true], ["updated_at", Wed, 14 Jan 2015 15:43:55 UTC +00:00]]
false ActsAsTaggableOn::Tag Load (0.2ms) SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."taggable_id" = $1 AND "taggings"."taggable_type" = $2 AND (taggings.context = 'tags' AND taggings.tagger_id IS NULL) [["taggable_id", 26], ["taggable_type", "Photo"]]
(6.1ms) COMMIT
Redirected to http://localhost:3000/users/enrique-isasi-4/photos/rustic-plastic-table
Completed 302 Found in 31ms (ActiveRecord: 9.7ms)

Why does validates_presence_of fail on save, even when the condition is not violated

In my Post.rb model, I am doing this:
validates_presence_of :body
In my controller I have this action that I am executing:
def mark_as_published
if #post.unpublished?
#post.published!
redirect_to post_path(#post), notice: "Successfully published."
else
redirect_to post_path(#post), notice: "Post already published"
end
end
This is the error I am getting:
app/controllers/posts_controller.rb:104:in `mark_as_published'
Started PUT "/posts/ebola-death-climbs-past-6-000/mark_as_published" for 67.230.41.168 at 2014-12-10 20:15:29 +0000
app[web.1]: ActiveRecord::RecordInvalid (Validation failed: Body can't be blank):
This is the record in the console:
> Post.last
=> #<Post id: 29, title: "Ebola death climbs past 6,000", photo: nil, body: "Fresh figures from WHO has revealed that the death...", created_at: "2014-12-10 20:08:58", updated_at: "2014-12-10 20:08:58", user_id: 10, ancestry: nil, file: nil, status: 2, slug: "ebola-death-climbs-past-6-000", publication_status: 0, has_eyewitness: false, youtube_embed_code: "", soundcloud_embed_code: "">
Why does this validation fail, only on the save/update, even though the post.body is not blank?
Edit 1
The publication_status is just an enum:
enum publication_status: [ :unpublished, :published ]
Which comes with a set of handy methods, including published?, unpublished?, published!, and unpublished!. The latter two basically toggle the value to be the flag, i.e. unpublished! changes the publication_status to be unpublished and vice versa.
Here are other validations on the Post.rb model:
validates_length_of :body, maximum: 150, too_long: 'The report must be less than 150 words.',
tokenizer: ->(str) { str.scan(/\w+/) }
validates_length_of :title, maximum: 7, too_long: 'The title must be less than 7 words.',
tokenizer: ->(str) { str.scan(/\w+/) }
Edit 2
This is what happens when I mark the record as published in the console:
0> p = Post.last
=> #<Post id: 29, title: "Ebola death climbs past 6,000", photo: nil, body: "Fresh figures from WHO has revealed that the death...", created_at: "2014-12-10 20:08:58", updated_at: "2014-12-10 20:08:58", user_id: 10, ancestry: nil, file: nil, status: 2, slug: "ebola-death-climbs-past-6-000", publication_status: 0, has_eyewitness: false, youtube_embed_code: "", soundcloud_embed_code: "">
irb(main):002:0> p.published!
=> true
irb(main):003:0> p.save
=> true
No SQL is generated. Not sure if this is because I am doing this in production on Heroku.
Edit 3
I tried to publish a record in development, and this is the SQL & server log:
Started PUT "/posts/longword-verylongword-longword-longword-longword-vellylongword-prettylongword/mark_as_published" for 127.0.0.1 at 2014-12-10 19:22:56 -0500
Processing by PostsController#mark_as_published as HTML
Parameters: {"authenticity_token"=>"8kYDxjYS54sGozjSS4ZZwQFJUTtIBgLpEmpAlTRZc4k=", "id"=>"longword-verylongword-longword-longword-longword-vellylongword-prettylongword"}
User Load (1.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1
(2.0ms) SELECT COUNT(*) FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = $1 AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 1]]
(1.2ms) SELECT COUNT(*) FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = $1 AND (((roles.name = 'editor') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 1]]
(0.2ms) BEGIN
(0.2ms) ROLLBACK
Completed 422 Unprocessable Entity in 62ms
ActiveRecord::RecordInvalid - Validation failed: Body can't be blank:
When I do it in the console, this is the log:
> p = Post.last
Post Load (0.6ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."id" DESC LIMIT 1
=> #<Post id: 37, title: "LongWord VeryLongWord LongWord LongWord LongWord V...", photo: nil, body: "10PP gives you a lot of one on one attention that ...", created_at: "2014-11-27 09:21:06", updated_at: "2014-11-27 09:21:06", user_id: nil, ancestry: nil, file: nil, status: 1, slug: "longword-verylongword-longword-longword-longword-v...", publication_status: 0, has_eyewitness: false, youtube_embed_code: "", soundcloud_embed_code: "">
[21] pry(main)> p.published!
(0.2ms) BEGIN
SQL (2.0ms) UPDATE "posts" SET "publication_status" = $1, "updated_at" = $2 WHERE "posts"."id" = 37 [["publication_status", 1], ["updated_at", "2014-12-11 00:24:18.419390"]]
FriendlyId::Slug Load (1.9ms) SELECT "friendly_id_slugs".* FROM "friendly_id_slugs" WHERE "friendly_id_slugs"."sluggable_id" = $1 AND "friendly_id_slugs"."sluggable_type" = $2 ORDER BY "friendly_id_slugs".id DESC LIMIT 1 [["sluggable_id", 37], ["sluggable_type", "Post"]]
(0.9ms) COMMIT
=> true
From the log I can see clearly you do not retrieve the Post from the database. So you are saving a "new/empty" post. Please verify how your #post variable is set. I am guessing you are using the incorrect before_action now, or your post retrieval is too liberal and defaults to a new post if not found?
One option, if and only if it works within your application's logic, is to limit the validation to creates:
validates_presence_of :body, on: :create
If your app's logic dictates that updates need to run the validation, it would be helpful to see more code in order to better know how #post is populated, what the published/unpublished? methods look like, etc.

How to do a nested includes for n + 1 in Rails

Here's what happens:
I have in my controller:
#products = Spree::Product.all_active
And in the model:
Spree::Product.class_eval do
def self.all_active
includes(:master)
.where('available_on IS NULL OR available_on < ?', Time.now).where(deleted_at: nil)
end
end
And in the view I'm calling something that will look like this:
#products.each do |product|
product.images.each do |image|
image.attachment.url(:product)
end
end
The log is showing something along the lines like this for every single product:
Spree::Image Load (2.6ms) SELECT "spree_assets".* FROM "spree_assets" WHERE "spree_assets"."type" IN ('Spree::Image') AND "spree_assets"."viewable_id" = $1 AND "spree_assets"."viewable_type" = $2 ORDER BY "spree_assets"."position" ASC [["viewable_id", 9], ["viewable_type", "Spree::Variant"]]
Spree::Price Load (0.3ms) SELECT "spree_prices".* FROM "spree_prices" WHERE "spree_prices"."variant_id" = $1 AND "spree_prices"."currency" = 'USD' LIMIT 1 [["variant_id", 9]]
CACHE (0.3ms) SELECT "spree_zone_members".* FROM "spree_zone_members" WHERE "spree_zone_members"."zone_id" = $1 [["zone_id", 2]]
CACHE (0.0ms) SELECT "spree_countries".* FROM "spree_countries" WHERE "spree_countries"."id" IN (204, 49)
CACHE (0.2ms) SELECT "spree_shipping_methods".* FROM "spree_shipping_methods" INNER JOIN "spree_shipping_methods_zones" ON "spree_shipping_methods"."id" = "spree_shipping_methods_zones"."shipping_method_id" WHERE "spree_shipping_methods"."deleted_at" IS NULL AND "spree_shipping_methods_zones"."zone_id" = $1 [["zone_id", 2]]
CACHE (0.0ms) SELECT "spree_calculators".* FROM "spree_calculators" WHERE "spree_calculators"."calculable_type" = 'Spree::ShippingMethod' AND "spree_calculators"."calculable_id" IN (3, 2, 1)
(0.8ms) SELECT COUNT(*) FROM "spree_assets" WHERE "spree_assets"."type" IN ('Spree::Image') AND "spree_assets"."viewable_id" = $1 AND "spree_assets"."viewable_type" = $2 [["viewable_id", 1], ["viewable_type", "Spree::Variant"]]
I also have the bullet gem installed and it is recommending me to do:
N+1 Query detected
Spree::Variant => [:images]
Add to your finder: :include => [:images]
N+1 Query detected
Spree::Variant => [:default_price]
Add to your finder: :include => [:default_price]
I'm not sure where to place this .includes. to find out where Spree::Variant is being called I went to the Rails console:
2.0.0-p481 :001 > Spree::Product.first
Spree::Product Load (1.8ms) SELECT "spree_products".* FROM "spree_products" WHERE "spree_products"."deleted_at" IS NULL ORDER BY "spree_products"."id" ASC LIMIT 1
=> #<Spree::Product id: 1, name: "Ruby on Rails Tote", description: "Debitis facilis impedit natus eos qui vero. Ut qua...", available_on: "2014-07-04 05:44:50", deleted_at: nil, slug: "ruby-on-rails-tote", meta_description: nil, meta_keywords: nil, tax_category_id: 1, shipping_category_id: 1, created_at: "2014-07-04 05:44:51", updated_at: "2014-07-04 05:45:30">
2.0.0-p481 :002 > Spree::Product.first.images
Spree::Product Load (0.8ms) SELECT "spree_products".* FROM "spree_products" WHERE "spree_products"."deleted_at" IS NULL ORDER BY "spree_products"."id" ASC LIMIT 1
Spree::Variant Load (1.0ms) SELECT "spree_variants".* FROM "spree_variants" WHERE "spree_variants"."deleted_at" IS NULL AND "spree_variants"."product_id" = $1 AND "spree_variants"."is_master" = 't' LIMIT 1 [["product_id", 1]]
Spree::Image Load (0.8ms) SELECT "spree_assets".* FROM "spree_assets" WHERE "spree_assets"."type" IN ('Spree::Image') AND "spree_assets"."viewable_id" = $1 AND "spree_assets"."viewable_type" = $2 ORDER BY "spree_assets"."position" ASC [["viewable_id", 1], ["viewable_type", "Spree::Variant"]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Spree::Image id: 21, viewable_id: 1, viewable_type: "Spree::Variant", attachment_width: 360, attachment_height: 360, attachment_file_size: 31490, position: 1, attachment_content_type: "image/jpeg", attachment_file_name: "ror_tote.jpeg", type: "Spree::Image", attachment_updated_at: "2014-07-04 05:45:28", alt: nil, created_at: "2014-07-04 05:45:29", updated_at: "2014-07-04 05:45:29">, #<Spree::Image id: 22, viewable_id: 1, viewable_type: "Spree::Variant", attachment_width: 360, attachment_height: 360, attachment_file_size: 28620, position: 2, attachment_content_type: "image/jpeg", attachment_file_name: "ror_tote_back.jpeg", type: "Spree::Image", attachment_updated_at: "2014-07-04 05:45:29", alt: nil, created_at: "2014-07-04 05:45:30", updated_at: "2014-07-04 05:45:30">]>
Where would I add :images and :default_price within this context?
try:
Spree::Product.class_eval do
def self.all_active
includes(master: { products: :images } )
.where('available_on IS NULL OR available_on < ?', Time.now).where(deleted_at: nil)
end
end
includes can be used to fetch multiple models, nested or not.
For those that came here purely for the title:
Post.includes(:user, :group, sub_category: :category)

Rails 4: can't update polymorphic nested resource through form

Just in the final stages of transferring an app stuck in Rails 2 on a shared server to Rails 4 on a VPS, but stuck on one thing.
I have an Image model that uses Carrierwave to upload and display attached images. The Image model has a polymorphic association to a couple of other models. The host and associated models are updated together on a combined multipart form.
The form works perfectly well for creating and editing the primary model and for creating and attaching new images, but the image attributes can't be edited, and no error is thrown to help.
Here are the relevant parts of my Image model:
class Image < ActiveRecord::Base
belongs_to :imagings, polymorphic: true, touch: true
mount_uploader :image, ImageUploader, mount_on: :image_file_name
end
And my Review model:
class Review < ActiveRecord::Base
has_many :images, as: :imagings, dependent: :destroy
accepts_nested_attributes_for :images, reject_if: lambda { |t| t['image'].nil? }, allow_destroy: true
end
And my Reviews Controller:
class ReviewsController < ApplicationController
def edit
#review = Review.find(params[:id])
3.times {#review.images.build}
end
def update
#review = Review.find(params[:id])
if #review.update(reviews_params)
redirect_to #review, notice: "Successfully updated review."
else
render :edit
end
end
private
def reviews_params
params.require(:review).permit(:title, :authors, :venue, :startdate, :enddate, :body, :approved, :company, :user_id, { images_attributes: [:title, :credits, :image, :_destroy, :id] })
end
end
I can add images to existing reviews or to a new review perfectly well with this setup, but if I try to change text fields for an existing image, the parameters show in the console but they are ignored:
Started PATCH "/reviews/492" for 127.0.0.1 at 2014-07-16 11:03:42 +0100
Processing by ReviewsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"HvrsCAXXvO4zIqTBw05qSUwU9I2241DXyilhswEbU9o=", "review"=>{"title"=>"Here's a new review", "authors"=>"", "company"=>"", "venue"=>"", "startdate"=>"2014-07-16", "enddate"=>"2014-07-31", "body"=>"<p>Something</p>", "images_attributes"=>{"0"=>{"title"=>"Doggie", "credits"=>"Icons galore", "_destroy"=>"0", "id"=>"1239"}, "1"=>{"title"=>"", "credits"=>""}, "2"=>{"title"=>"", "credits"=>""}, "3"=>{"title"=>"", "credits"=>""}}, "user_id"=>"4", "approved"=>"1"}, "commit"=>"Update Review", "id"=>"492"}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 1]]
Review Load (0.3ms) SELECT "reviews".* FROM "reviews" WHERE "reviews"."id" = $1 LIMIT 1 [["id", 492]]
(12.4ms) BEGIN
Image Load (0.4ms) SELECT "images".* FROM "images" WHERE "images"."imagings_id" = $1 AND "images"."imagings_type" = $2 AND "images"."id" IN (1239) [["imagings_id", 492], ["imagings_type", "Review"]]
(0.2ms) COMMIT
Redirected to http://127.0.0.1:3000/reviews/492
Completed 302 Found in 27ms (ActiveRecord: 13.6ms)
You can see here how the images attribute for credit has the change to "Icons galore", but the SQL only fetches the linked image without updating it. Contrast this with the following update to the main model which does a select followed by an update between the BEGIN and COMMIT.
Started PATCH "/reviews/492" for 127.0.0.1 at 2014-07-16 11:26:01 +0100
Processing by ReviewsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"HvrsCAXXvO4zIqTBw05qSUwU9I2241DXyilhswEbU9o=", "review"=>{"title"=>"Here's a new review", "authors"=>"", "company"=>"", "venue"=>"", "startdate"=>"2014-07-16", "enddate"=>"2014-07-31", "body"=>"<p>Something else</p>", "images_attributes"=>{"0"=>{"title"=>"Doggie", "credits"=>"Icons", "_destroy"=>"0", "id"=>"1239"}, "1"=>{"title"=>"", "credits"=>""}, "2"=>{"title"=>"", "credits"=>""}, "3"=>{"title"=>"", "credits"=>""}}, "user_id"=>"4", "approved"=>"1"}, "commit"=>"Update Review", "id"=>"492"}
User Load (6.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 1]]
Review Load (0.3ms) SELECT "reviews".* FROM "reviews" WHERE "reviews"."id" = $1 LIMIT 1 [["id", 492]]
(18.1ms) BEGIN
Image Load (0.5ms) SELECT "images".* FROM "images" WHERE "images"."imagings_id" = $1 AND "images"."imagings_type" = $2 AND "images"."id" IN (1239) [["imagings_id", 492], ["imagings_type", "Review"]]
SQL (5.9ms) UPDATE "reviews" SET "body" = $1, "updated_at" = $2 WHERE "reviews"."id" = 492 [["body", "<p>Something else</p>"], ["updated_at", "2014-07-16 10:26:01.455481"]]
(24.8ms) COMMIT
Redirected to http://127.0.0.1:3000/reviews/492
Completed 302 Found in 120ms (ActiveRecord: 56.0ms)
Yet if I try to make the same update in the Rails console, it sometimes works perfectly:
2.1.1 :062 > review = Review.find(492)
Review Load (0.5ms) SELECT "reviews".* FROM "reviews" WHERE "reviews"."id" = $1 LIMIT 1 [["id", 492]]
=> #<Review id: 492, title: "Here's a new review", authors: "", venue: "", startdate: "2014-07-16", enddate: "2014-07-31", body: "<p>Something else</p>", approved: true, created_at: "2014-07-16 09:38:33", updated_at: "2014-07-16 10:26:01", user_id: 4, company: "">
2.1.1 :064 > review.images.first.title = "Doggies galore"
=> "Doggies galore"
2.1.1 :066 > review.save
(0.8ms) BEGIN
SQL (7.5ms) UPDATE "images" SET "title" = $1, "updated_at" = $2 WHERE "images"."id" = 1239 [["title", "Doggies galore"], ["updated_at", "2014-07-16 10:32:39.109784"]]
Review Load (0.3ms) SELECT "reviews".* FROM "reviews" WHERE "reviews"."id" = $1 LIMIT 1 [["id", 492]]
SQL (1.7ms) UPDATE "reviews" SET "updated_at" = '2014-07-16 10:32:39.129314' WHERE "reviews"."id" = 492
(1.6ms) COMMIT
=> true
And sometimes doesn't:
2.1.1 :082 > review = Review.find(492)
Review Load (0.3ms) SELECT "reviews".* FROM "reviews" WHERE "reviews"."id" = $1 LIMIT 1 [["id", 492]]
=> #<Review id: 492, title: "Here's a new review", authors: "", venue: "", startdate: "2014-07-16", enddate: "2014-07-31", body: "<p>Something else</p>", approved: true, created_at: "2014-07-16 09:38:33", updated_at: "2014-07-16 10:38:30", user_id: 4, company: "">
2.1.1 :083 > review.images.first.credits = "Icons galore"
Image Load (0.5ms) SELECT "images".* FROM "images" WHERE "images"."imagings_id" = $1 AND "images"."imagings_type" = $2 ORDER BY "images"."id" ASC LIMIT 1 [["imagings_id", 492], ["imagings_type", "Review"]]
=> "Icons galore"
2.1.1 :084 > review.save!
(0.2ms) BEGIN
(0.3ms) COMMIT
=> true
2.1.1 :085 > review.images.first
Image Load (0.8ms) SELECT "images".* FROM "images" WHERE "images"."imagings_id" = $1 AND "images"."imagings_type" = $2 ORDER BY "images"."id" ASC LIMIT 1 [["imagings_id", 492], ["imagings_type", "Review"]]
=> #<Image id: 1239, title: "Doggies", credits: "Icons", created_at: "2014-07-16 09:38:33", updated_at: "2014-07-16 10:38:30", image_file_name: "ddad7b05-3430-49ed-b129-fd484ac793ad.gif", image_content_type: nil, image_file_size: nil, image_updated_at: nil, imagings_id: 492, imagings_type: "Review", original_filename: "Doggie.gif">
2.1.1 :086 >
I know I'm missing something obvious. Can anyone help please?
I think that you need to make a small change in reviews_params def as follows:
def reviews_params
params.require(:review).permit(:title, :authors, :venue, :startdate, :enddate, :body, :approved, :company, :user_id, images_attributes => [:title, :credits, :image, :_destroy, :id] )
end
Does that work?
i don't think you need the curly braces. Try removing them. Usually nested attributes are listed as a symbol which maps to an array of symbols(attributes). They are separated from attributes of the model in question with just a comma. So something such as,
params.require(:review).permit(:title, :authors, :venue, :startdate, :enddate, :body, :approved, :company, :user_id, :images_attributes => [:title, :credits, :image, :_destroy, :id] ) should work.

Resources