Issue migrating Rails 3.2 :includes call to Rails 4 - ruby-on-rails-4

I'm upgrading a Rails application from v3.2.13 to v4.1.5. Consider the following models.
class Camera::Clip < ActiveRecord::Base
belongs_to :camera
def self.cleanup(opts)
# blah blah method stuff
system_clips = Camera::Clip.includes(:camera).where(['cameras.control_system_id = ?', opts[:control_system_id]])
# In Rails 4, raises Mysql2::Error: Unknown column 'cameras.control_system_id'
end
end
class Camera < ActiveRecord::Base
belongs_to :control_system
has_many :clips, dependent: :destroy
# rest of class
end
I can get the method to function as it had originally by changing the :includes call to :joins, but why is that necessary? I thought :includes used a LEFT OUTER JOIN call on the database to combine the resources?

This may have been lost on me in Release Notes documentation, but a second step is needed to tell the where clause what I mean by 'cameras'.
This documentation pointed me to the :references method.
Swapping out the line for
Camera::Clip.includes(:camera).where('cameras.control_system_id = 13').references(:camera)
shows the exact same output in the Rails console as my environment running in Rails 3.2.13, with no error! Great success.

Related

undefined method `expr' for nil:NilClass after upgrading to rails 5.2

I have two following models
class Machine < ApplicationRecord
has_many :machine_part_changes
has_one :current_identifier_part_change, -> {
sql = <<-SQL
INNER JOIN "machine_parts"
ON "machine_parts"."id" = "machine_part_changes"."machine_part_id"
AND "machine_parts"."is_machine_external_identifier" = 1
SQL
installed.joins(sql)
},
class_name: 'MachinePartChange'
end
class MachinePartChange < ApplicationRecord
belongs_to :machine_part
belongs_to :machine, touch: true
end
in rails 4.2 I was able to do like
Machine.eager_load(:current_identifier_part_change).first
but now after I upgrade to rails 5.2 I am getting following error when I run tests.
Failure/Error: machine = Machine.eager_load(:current_identifier_part_change).find(create_machine.id)
NoMethodError:
undefined method `expr' for nil:NilClass
I do not have much knowledge of sql :-( and code is written some other developer what can I do to pass this test.

NoMethodError - new since upgrading to Rails 4

I'm at my wit's end. I upgraded to Rails 4.2.10, and everything is terrible.
Here is the relevant part of /models/product.rb
class Product < ActiveRecord::Base
delegate_attributes :price, :is_master, :to => :master
And here is /models/variant.rb:
class Variant < ActiveRecord::Base
belongs_to :product
The variants table has fields for "price" and "is_master". Products table does not.
It used to be the case that one could access Product.price and it would get/set the price for the master variant (there's really only one variant per product, the way things are currently set up).
Now it complains that:
NoMethodError: undefined method `price=' for #<Product:0x0000000d63b980>
It's true. There's no method called price=. But why wasn't this an issue before, and what on earth should I put in that method if I create it?
Here's the code to generate a product in db/seeds.rb:
product = Product.create!({
name: "Product_#{i}",
description: Faker::Lorem.sentence,
store_id: u.store.id,
master_attributes: {
listing_folder_id: uuids[i],
version_folder_id: uuids[i]
}
})
product.price = 10
product.save!
end
delegate_attributes isn't a Rails method and looks like it comes from a gem (or gems) that aren't actively maintained?
If there's a new version of whatever gem you're using that might help, because the short answer is that part of the "delegating" of an attribute would involve getting and setting the attribute, so it would generate #price= for you.
If you want to define it yourself, this should do it (within your Product class):
def price=(*args)
master.price=(*args)
end
or if you want to be more explicit:
def price=(amount)
master.price = amount
end

Trying to set up default_scope but getting "Support for calling #default_scope without a block is removed" error

I’m using Rails 4.2.3. I have these two models
class Address < ActiveRecord::Base
…
has_one :user
and
class User < ActiveRecord::Base
belongs_to :address
default_scope includes(:address)
I want to auto-load my parent association when I load my “MyObject” but I’m getting this error on the “default_scope” line …
Support for calling #default_scope without a block is removed. For example instead of `default_scope where(color: 'red')`, please use `default_scope { where(color: 'red') }`. (Alternatively you can just redefine self.default_scope.)
How do I adjust my “default_scope” line to auto-load my parent association?
You are missing block in your line, Change it like this:
default_scope { includes(:address) }

Eager Loading Multiple Associations and serialization

In my project I have 3 models Assignment, Question and MultipleChoice with the following associations
assignment.rb
has_many :questions, dependent: :destroy
question.rb
belongs_to :assignment, class_name: 'Assignment', foreign_key: :assignment_id
has_many :multiple_choices, dependent: :destroy
multiple_choice.rb
belongs_to :question
Now I want to make a query like below
#assignment = Assignment.find(params[:id])
#questions = #assignment.questions.includes(:multiple_choices)
This is not working as expected.
So, I want all questions that belongs to the assignment for the params[:id] and the associated multiple choices that belongs to a question. My above query do not give any error but it only show questions not multiple choices associated with question. How can I do this? I am learning api development for rails. So I want to send this value as json and probably I will need serialization. How can I do this? I am working on rails 4.
Edit
well the output for
#questions = #assignment.questions.includes(:multiple_choices) and
#questions = #assignment.questions.eager_load(:multiple_choices) and
#questions = #assignment.questions are all same.
I dont understand why the output do not include any value from multiple choices table
Output of the command
#assignment.questions.eager_load(:multiple_choices).to_sql id
=> "SELECT \"questions\".\"id\" AS t0_r0, \"questions\".\"content\" AS t0_r1, \"questions\".\"q_type\" AS t0_r2, \"quest
ions\".\"created_at\" AS t0_r3, \"questions\".\"updated_at\" AS t0_r4, \"questions\".\"assignment_id\" AS t0_r5, \"multi
ple_choices\".\"id\" AS t1_r0, \"multiple_choices\".\"content\" AS t1_r1, \"multiple_choices\".\"created_at\" AS t1_r2,
\"multiple_choices\".\"updated_at\" AS t1_r3, \"multiple_choices\".\"question_id\" AS t1_r4 FROM \"questions\" LEFT OUTE
R JOIN \"multiple_choices\" ON \"multiple_choices\".\"question_id\" = \"questions\".\"id\" WHERE \"questions\".\"assignm
ent_id\" = $1"
The behaviour for includes function changed in Rails 4. You can find more details here:
http://blog.arkency.com/2013/12/rails4-preloading/
I also suppose, that if you will use eager_load instead of includes, you will get the result you need.
#assignment is an object from which you are getting the questions.
But with #questions = #assignment.questions.includes(:multiple_choices) how can you get the multiple_choices without calling this on an object?
Try this->
#assignment = Assignment.includes(:questions).find(params[:id])
#assignment.questions.includes(:multiple_choices).collect {|question| question.multiple_choices }
This also includes eager loading.
Hope you'll get what you expect.

Using CanCan with Polymorphic Associations

I am struggling to use CanCan with my polymorphic associations. It is breaking down when I try and load the polymorphic objects in my controller.
class Trip < ActiveRecord::Base
has_many :images, as: :viewable
end
class Image < ActiveRecord::Base
belongs_to :viewable, polymorphic: true
end
Now I have a controller that deals specifically with images assigned to a trip.
class TripImagesController < ApplicationController
load_and_authorize_resource :trip
load_and_authorize_resource :image, through: :trip
def index
end
end
However, when I hit this index action I get the following error:
Couldn't find Image with id= [WHERE "images"."viewable_id" = $1 AND "images"."viewable_type" = $2]
I can see the query being executed in the Rails logs:
SELECT "images".* FROM "images" WHERE "images"."viewable_id" = $1 AND "images"."viewable_type" = $2 AND "images"."id" = $3 LIMIT 1 [["viewable_id", 1], ["viewable_type", "Trip"], ["id", ""]]
So the select statement looks good, except that it's trying to find only a single image (even though I'm in an index action). It's specifying an image id (which obviously does not exist in the route params) and it's also limiting the result to a single row.
This is using Rails 4.0.2 and CanCan 1.6.10. What am I missing here?