AR.to_json Works in Console, Fails in Browser - ruby-on-rails

I have this block of code:
users = Array.new
users << User.find(:all, :conditions => ["email like ?", "%foo%"])
users << User.find(:all, :conditions => ["name like ?", "%bar%"])
users.flatten!
users.uniq!
puts users.to_json :include => [:licenses]
When I run it using script/console, it returns exactly what you would think it should, a JSON representation of the Array of users that I found, flattened, and uniquified. But running that same line of code as part of a search_for_users method, I get this error
TypeError in ControllerName#search_for_users
wrong argument type Hash (expected Data)
and the line referenced is the line with the .to_json call.
It's baffling me because the code is verbatim the same. The only difference is that when I'm running it in the console, I'm entering the conditions manually, but in my method, I'm pulling the query from params[:query]. But, I just tried hardcoding the queries and got the same result, so I don't think that is the problem. If I remove the :include, I don't see the error, but I also don't get the data I want.
Anyone have any idea what the issue might be?

There are a few plugins and gems that can cause .to_json to fail if included in your controller. I believe that the Twitter gem is one of them (ran into a problem with this awhile back).
Do you have "include [anything]" or "require [anything]" in this controller?
If not, I'd suggest temporarily removing any plugins you're using to troubleshoot, etc.
Finally, what happens if you replace that entire controller action with simply:
%w(1 2 3 4 5).to_json
That should help you pin down what is failing.

Whenever code in tests or the console behaves different from production environment (which is a guess... you might be running your site in development mode), this calls for a load order issue. In production environment, all the models and controllers are preloaded, in other environments they are loaded lazily when needed.
Start your console with RAILS_ENV=production ./script/console and see if you can reproduce the error this way.
As cscotta mentioned, there are a couple of gems and librarys, that can interfere with .to_json, first to mention the functionality, that you get when you require 'json'. I personally ran into several issues with that.
Hope this helps
Seb

Related

Updating a Rails model's attributes through mongoid using normal persistence methods

I have been chasing an issue down for a while now, and still cannot figure out what's happening. I am unable to edit documents made from my gem through normal persistence methods, like update or even just editing attributes and calling save.
For example, calling:
Scram::Policy.where(id: a.id).first.update!(priority: 12345)
Will not work at all (there are no errors, but the document has not updated). But the following will work fine:
Scram::Policy.collection.find( { "_id" => a.id } ).update_one( { "$set" => {"priority" => 12345}})
I am not sure what I'm doing wrong. Calling update and save on any other model works fine. The document in question is from my gem: https://github.com/skreem/scram/blob/master/lib/scram/app/models/policy.rb
I cannot edit its embedded documents either (targets). I have tried removing the store_in macro, and specifying exactly what class to use using inverse_of and class_name in a fake app to reimplement these classes: https://github.com/skreem/scram-implementation/blob/master/lib/scram/lib/scram/app/models/policy.rb
I've tried reimplementing the entire gem into a clean fake rails application: https://github.com/skreem/scram-implementation
Running these in rails console demonstrates how updating does not work:
https://gist.github.com/skreem/c70f9ddcc269e78015dd31c92917fafa
Is this an issue with mongoid concerning embedded documents, or is there some small intricacy I am missing in my code?
EDIT:
The issue continues if you run irb from the root of my gem (scram) and then run the following:
require "scram.rb"
Mongoid.load!('./spec/config/mongoid.yml', :test)
Scram::Policy.first.update!(priority: 32) #=> doesn't update the document at all
Scram::Policy.where(id: "58af256f366a3536f0d54a61").update(priority: 322) #=> works just fine
Oddly enough, the following doesn't work:
Scram::Policy.where(id: "58af256f366a3536f0d54a61").first.update(priority: 322)
It seems like first isn't retrieving what I want. Doing an equality comparison shows that the first document is equal to the first returned by the where query.
Well. As it turns out, you cannot call a field collection_name or else mongoid will ensure bad things happen to you. Just renaming the field solved all my issues. Here's the code within mongoid that was responsible for the collision: https://github.com/mongodb/mongoid/blob/master/lib/mongoid/persistence_context.rb#L82
Here's the commit within my gem that fixed my issue: https://github.com/skreem/scram/commit/25995e955c235b24ac86d389dca59996fc60d822
Edit:
Make sure to update your Mongoid version if you have dealt with this issue and did not get any warnings! After creating an issue on the mongoid issue tracker, PersistenceContext was added to a list of prohibited methods. Now, attempting to use collection_name or collection as a field will cause mongoid to spit out a couple of warnings.
Fix commit: https://github.com/mongodb/mongoid/commit/6831518193321d2cb1642512432a19ec91f4b56d

methods for debugging slow queries in active model serializers?

I am having difficulty optimizing my Active Model Serializers to avoid the n+1 problem. As per suggestions from their docs, I have attempted to eager load the associations which i thought were causing my query bottlenecks, but my serializers are still taking forever.
Obviously, i must be doing something wrong. My application is deeply nested with associations, so i guess I'm more interested in discovering a tool to unveil to me exactly WHICH associations are costing me. Right now, i am attaching a stack trace to every query run through the ActiveRecord
ActiveSupport::Notifications.subscribe("sql.active_record") do |_, _, _, _, details|
puts caller.join("\n")
puts "*" * 50
end
which gives me a ridiculous output because i am running so many queries to begin with, but, in addition, the stack traces are not helpful at identifying which serializer is at fault. It shows me which controller method was calling render, but then from there the stack trace simply prints methods from gems/active_model_serializers, which does not help me.
I am hoping to uncover a method of debugging that would be able to identify to me which serializers were at fault, that way i am not guessing at how to optimize my queries. Has anybody discovered anything like this? Thanks!
===================
UPDATE
Just so it is clear, i am already printing a query log, in addition to a stack trace. Unfortunately, with so many associations to keep track of, the query log is not exactly helpful at identifying the source of the query. It is guess work at best, and ineffective at the association scope i am dealing with.
I have abandoned the stack traces altogether, finding them to be totally unhelpful. Now, all i have printing are SQL logs, and i am manually sifting through them, trying to discover the source of the association.
The next method I will attempt (although i hate to resort to it) is commenting out associations until i see improvements in my query times. It will be more effective than trying to trace the source of the problem, but it will provide me no comfort in a production environment (where commenting out critical associations is not an option), so if anybody finds a solution that can help, I would still be very grateful.
I will continue to post updates as I move through this problem, as it may help many others in the future.
======================UPDATE 2
It turns out that commenting out associations in my serializer and reintroducing them one at a time, while ineffective in production, is an excellent way to debug in a local environment. I was able to drill down to the problem within a minute and correct it. Still, this is not an ideal solution. I would ideally like to be able to identify the problem from a log so that in production i could ascertain the issue without affecting the application's behavior.
The active_record_query_trace gem can do that.
Add the following to your Gemfile:
group :development do
gem 'active_record_query_trace'
end
Create an initializer such as config/initializers/active_record_query_trace.rb to enable the gem. If you want to customize how the gem behaves, you can add any combination of the options described in the docs to the initializer as well.
if Rails.env.development?
ActiveRecordQueryTrace.enabled = true
# Optional: other gem config options go here
end
Restart the Rails development server.
Easy way within any gems - is logging each string of code. For example, if you have
that code of serializer:
module Flats
class IndexSerializer < Api::V2::RealtyObjects::IndexSerializer
attributes(
:flat_number,
:entrance_number,
:floor_in_house,
:live_area,
:room_count,
:total_area,
)
end
end
add method which will be log time to your development.log on each attribute:
module Flats
class IndexSerializer < Api::V2::RealtyObjects::IndexSerializer
attribute_list = %i[
flat_number
entrance_number
floor_in_house
live_area
room_count
total_area
]
attributes(*attribute_list)
def logger(name, value)
Rails.logger.debug name, value, "#{Time.now.strftime('%M:%S--%N')}"
end
attribute_list.each do |attribute_name|
define_method attribute_name do |value|
logger(attribute_name, value)
super
end
end
end
end

Phusion Passenger Error using .all function - is there a backwards compatible method?

I previously posted a question (Performing multiple queries on the same model efficiently) which fellow StackExchange users kindly answered and saved me lots of processing time, avoiding lots of queries on my model by storing the results of a SQL query using the .all function
Specifically they advised #chosenrecords = Everything.where('name LIKE ?', 'What I want').order('price ASC').all be used
This appeared to work fantastically and I used it in a number of places in our code, however, having just uploaded it onto a live server I get an error message from Phusion Passenger for every line in which .all features.
The error is syntax error, unexpected '.', expecting kEND .order('price ASC').all
I have previously tried to gather information from the company hosting our sites regarding the versions of rails and passenger they're using, but without any success. In the past anything that has worked locally has also worked on the server, provided I use Ruby 1.9.3 i386-mingw32.
Can anyone advise how I could fix this error? Is there an older function that does the equivalent operation and may work on the server?
Discovered that the old version of Passenger appears to be less robust to code falling across 2 lines, essentially I changed
#chosenrecords = Everything.where('name LIKE ?', 'What I want')
.order('price ASC').all
to the following and it works a dream
#chosenrecords = Everything.where('name LIKE ?', 'What I want').order('price ASC').all
Hopefully someone else will benefit from the errors of my ways!
Actually that's not a Passenger problem, nor is it a matter of "less robust to code falling across 2 lines". The problem is this:
The first code exhibit is illegal Ruby syntax. If you to chain a to #order like that, you have to ensure that the first line ends with a dot. Otherwise Ruby will think that the first line is a single, complete statement, with the second one also being a single complete statement. Obviously a Ruby statement cannot begin with a dot, so in your first code exhibit, the second line raises a syntax error.

Rails association fails on Heroku but works on local box?

Why would I get NoMethodError on my Heroku app when the same code works flawlessly on my local setup?
The error is triggered by this code:
#customer = Customer.find(1)
#customer.responses.create(:offer_id => '1', :digit => '2')
That code works as intended on my local server and in my local Rails console.
However, on Heroku the above code triggers NoMethodError:
NoMethodError (undefined method `responses' for #<Customer:0x7f7bcbee3808>):
The Response model is tied to the Customer model by means of belongs_to :customer
Additionally, I can login to the Heroku console and run this without any problems:
Response.create(:offer_id => '1', :customer_id => '1', :digit => '2')
So if the above works and both versions work fine on my local box, why would the association fail on Heroku?
--
Running Rails 3.0.6 and tested on Heroku Ruby 1.8.7 and Ruby 1.9.2
Databases are identical on Heroku and on my local box.
Usually when something like this doesn't work it indicates you're missing a has_many association. You need to define both the belongs_to and has_many sides of the association if you wish to access them both.
By the sounds of it, if it's working on your local machine but not Heroku then it would be because you haven't pushed the changes to the Heroku server and restarted the console there. Please make sure you have pushed the changes and try again.
Marco, I thought about this a bit, and I have a few guesses for you to try. Before you do either of these, restart your app. Sometimes that does miracles.
heroku restart
Ok, now, try in console just
#customer.responses
What does that return? I assume it should be []. Maybe doing some inspection etc. of that can give us insights here. If you build and associate a response manually can you get it to show up?
Second, your no method error is on responses, not on create, so whatever you type after that probably doesn't matter, BUT, are your offer_id and digit fields integers? If so, try creating them using integers, not strings. PostgreSQL is so fragile compared to MySQL or SQLite, I've had loads of issues that trace back to my unfamiliarity working with Postgre prior to developing on Heroku.
#customer.responses.create(:offer_id=>1,:digit=>3)
That probably doesn't matter but it's worth checking out.
The other thing to check is all your callbacks and validations etc. Is anything failing? It may not seem related but I've had issues before where things acted very weird because of seemingly tiny silent failures in a callback that I had overlooked. I'm sure you're testing as you go, but if you've got shallow test coverage anywhere on this model you might as well use this bug hunt as a chance to beef it up :)
Sympathies on the error, I don't know if any of this will help, but good luck! Please post if Heroku staff find the issue, I'd be very interested to learn from it!
I think you problem is how you are creating the response:
#customer.responses.create(:offer_id => '1', :digit => '2')
You might want to try this instead.
Response.create(:offer_id => '1', :digit => '2', :customer_id => 1)

Rails test db doesn't persist record changes

I've been trying to solve a problem for a few weeks now. I am running rspec tests for my Rails app, and they are working fine except for one error that I can't seem get my head around.
I am using MySQL with the InnoDB engine.
I have set config.use_transactional_fixtures = true in spec_helper.rb
I load my test fixtures manually with the command rake spec:db:fixtures:load.
The rspec test is being written for a BackgrounDRb worker, and it is testing that a record can have its state updated (through the state_machine gem).
Here is my problem:
I have a model called Listings. The rspec test calls the update_sold_items method within a file called listing_worker.rb.
This method calls listing.sell for a particular record, which sets the listing record's 'state' column to 'sold'.
So far, this is all working fine, but when the update_sold_items method finishes, my rspec test fails here:
listing = Listing.find_by_listing_id(listing_id)
listing.state.should == "sold"
expected: "sold",
got: "current" (using ==)
I've been trying to track down why the state change is not persisting, but am pretty much lost. Here is the result of some debugging code that I placed in the update_sold_items method during the test:
pp listing.state # => "current"
listing.sell!
listing.save!
pp listing.state # => "sold"
listing.reload
pp listing.state # => "current"
I cannot understand why it saves perfectly fine, but then reverts back to the original record whenever I call reload, or Listing.find etc.
Thanks for reading this, and please ask any questions if I haven't given enough information.
Thanks for your help,
Nathan B
P.S. I don't have a problem creating new records for other classes, and testing those records. It only seems to be a problem when I am updating records that already exist in the database.
I suspect, like nathan, transaction issues. Try putting a Listing.connection.execute("COMMIT") right before your first save call to break the transaction and see what changes. That will break you out of the transaction so any additional rollback calls will be non-effectual.
Additionally, by running a "COMMIT" command, you could pause the test with a debugger and inspect the database from another client to see what's going on.
The other hypothesis, if the transaction experimentation doesn't yield any results, is that perhaps your model really isn't saving to the database. Check your query logs. (Specifically find the update query).
These kind of issues really stink! Good luck!
If you want to investigate what you have in DB while running tests you might find this helpful...
I have a rspec test where I save #user.save and it works like a charm, but then I wanted to see if it's really saved in the DB.
I opened rails console for test environment
rails c test
ran
User.all
and as expected got nothing
I ran my spec that contains:
user_attr_hash = FactoryGirl.attributes_for(:user)
#user = User.new user_attr_hash
#user.save
binding.pry
I thought that stopping the test after save would mean that it's persisted, but that's not the case. It seems that COMMIT on the connection is fired later (I have no idea when:\ )
So, as #Tim Harper suggests, you have to fire that commit yourself in the pry console:
pry(#<RSpec::Core::ExampleGroup::Nested_1>)> User.connection.execute("COMMIT")
Now, if you run User.all in your rails console you should see it ;)

Resources