Problem with Thinking Sphinx and Functional Tests - ruby-on-rails-3

this is my test (with shoulda helpers):
context "searching from header" do
setup do
Factory(:city, :name => 'Testing It')
ThinkingSphinx::Test.index 'city_core', 'city_delta'
ThinkingSphinx::Test.start
get :index,
:query => 'Testing It'
end
should respond_with(:success)
should assign_to(:results)
should "have one city on the result" do
assert_equal( assigns(:results).count, 1 )
assert_kind_of( assigns(:results).first, City )
end
ThinkingSphinx::Test.stop
end
Everything works fine except the test always say the count of the results is 0, not 1.
I have debugged this code and when the request reaches the controller, the Sphinx indexes are completely empty, even with the explicit call of index for it.
Am I doing something wrong here?
Any help appreciated.

I found out the problem... even tho the insertion in the database is right before the ThinkingSphinx.index, with transactional fixtures, after the setup block the records get deleted.
The solution was adding to the test the following line:
self.use_transactional_fixtures = false
Hope this helps anyone with the same problem.

Related

How do I get the results of the Plucky Query inside my controller?

I'm missing something simple - I do not want to access the results of this query in a view.
Here is the query:
#adm = Admin.where({:id => {"$ne" => params[:id].to_s},:email => params[:email]})
And of course when you inspect you get:
#adm is #<MongoMapper::Plugins::Querying::DecoratedPluckyQuery:0x007fb4be99acd0>
I understand (from asking the MM guys) why this is the case - they wished to delay the results of the actual query as long as possible, and only get a representation of the query object until we render (in a view!).
But what I'm trying to ascertain in my code is IF one of my params matches or doesn't match the result of my query in the controller so I can either return an error message or proceed.
Normally in a view I'm going to do:
#adm.id
To get the BSON out of this. When you try this on the Decorated Query of course it fails:
NoMethodError (undefined method `id' for #<MongoMapper::Plugins::Querying::DecoratedPluckyQuery:0x007fb4b9e9f118>)
This is because it's not actually a Ruby Object yet, it's still the query proxy.
Now I'm fundamentally missing something because I never read a "getting started with Ruby" guide - I just smashed my way in here and learned through brute-force. So, what method do I call to get the results of the Plucky Query?
The field #adm is set to a query as you've seen. So, to access the results, you'll need to trigger execution of the query. There are a variety of activation methods you can call, including all, first, and last. There's a little documentation here.
In this case, you could do something like:
adm_query = Admin.where({:id => {"$ne" => params[:id].to_s},:email => params[:email]})
#adm_user = adm_query.first
That would return you the first user and after checking for nil
if #adm_user.nil?
# do something if no results were found
end
You could also limit the query results:
adm_query = Admin.where( ... your query ...).limit(1)

Whats the right way to test an array of model values in rspec?

I've yet to get my head around the rspec way of writing tests, but would appreciate some help in understanding what I've done wrong with this test.
describe Source do
describe "Upcase name" do
names = {'bob' => 'Bob',
'edward jones' => 'Edward Jones'
'Edward jones' => 'Edward Jones'}
names.each do |name,expect|
before { #source = Source.create(name: name) }
after { #source.destroy! }
it "source #{name} should be #{expect}" do
subject { #source }
#source.name.should == expect
let!(:find) do
Source.find_by_proper_name(expect)
end
it "should find" do
should == find
end
end
end
end
end
I have a unique constraint on the name column of the source model.
Every iteration of the test comes back as a failure due to unique violation. (even though I thought it would create only one model per iteration.
If I take out the middle of the three so all names are unique if it creates all at once - then the tests fail because #source is equal to the last value in all tests.
Essentially I want a DRY way to write the tests
Source.create(name: "bob").name.should == "Bob"
Source.create(name: "edward jones").name.should == "Edward Jones"
Source.create(name: "Edward jones").name.should == "Edward Jones"
How should I go about it?
you are mixing a lot of stuff in there...
first things first:
do not nest it
do not use let in it they belong in context
do not iterate its iterate in the it
do not cleanup the db yourself, use database cleaner or transactional fixtures or something like that
have a look at how i do spec like these, maybe this helps you somehow: https://github.com/phoet/on_ruby/blob/master/spec/models/user_spec.rb#L15

How to issue a 'find' or 'where' that raises a RecordNotFound

When I call a find with an id, it becomes a targeted find, and will throw an error RecordNotFound.
Foo::Bar.find(123) # RecordNotFound if no Bar with id 123 exists.
But when I call that with conditions, I get nil if not found:
Foo::Bar.find(:first, :conditions => [ "lower(name) = ?", name.downcase ])
I want such a conditional search to raise an error too. I know I can do:
Foo::Bar.find_by_name!("CocktailBar") #=> raises Recordnotfount if not not found.
But that has only really simple conditions. Mine need a little more complexity; actually something like:
Foo.Bar.select{ |pm| pm.name.downcase =~ /cocktail/}.first
And, if nothing is found, I want it to raise the RecordNotFound error. Is that possible at all? Or should I simply add some code to check against nil? and if nil? raise the error myself? And if so, how do I do that in Rails 3?
In the last snippet of code you are actually fetching all records from DB and then doing select on a Ruby array. It has nothing to do with ActiveRecord, so you can do whatever you like to raise exception manually, either use the code suggested by Douglas, or if, or unless etc. But it seems that you don't quite understand what your code does. Your select {...} is not translated into SQL SELECT ... WHERE(...).
If you need an exception raised automatically by ActiveRecord query, use this:
Foo::Bar.where([ "lower(name) = ?", name.downcase ]).first!
The equivalent bang methods exist for find_by methods as well, for example Foo::Bar.find_by_name!(name)
For anyone coming across this question, now you have the method find_by!
that does exactly what the OP asked for the find case.
example:
Foo::Bar.find_by!(name: "CocktailBar")
https://apidock.com/rails/v4.0.2/ActiveRecord/FinderMethods/find_by%21
Your final paragraph is what you need to do. Either check against nil, or raise the exceptions yourself. To raise the exception yourself, do the following:
Foo::Bar.find(:first, :conditions => [ "lower(name) = ?", name.downcase ]) || raise(ActiveRecord::RecordNotFound)

How can I test :inclusion validation in Rails using RSpec

I have the following validation in my ActiveRecord.
validates :active, :inclusion => {:in => ['Y', 'N']}
I am using the following to test my model validations.
should_not allow_value('A').for(:active)
should allow_value('Y').for(:active)
should allow_value('N').for(:active)
Is there a cleaner and more through way of testing this? I am currently using RSpec2 and shoulda matchers.
EDIT
After some looking around I only found, this probably an 'ok' way of testing this, shoulda does not provide anything for this and anyone who requires it can write their own custom matcher for it.(And probably contribute it back to the project). Some links to discussions that might be intresting:
Links which indicate to the above . Link 1 , Link 2
should_ensure_value_in_range This one comes close to what can be used, but only accepts ranges and not a list of values. Custom matcher can be based on this.
Use shoulda_matchers
In recent versions of shoulda-matchers (at least as of v2.7.0), you can do:
expect(subject).to validate_inclusion_of(:active).in_array(%w[Y N])
This tests that the array of acceptable values in the validation exactly matches this spec.
In earlier versions, >= v1.4 , shoulda_matchers supports this syntax:
it {should ensure_inclusion_of(:active).in_array(%w[Y N]) }
If you have more elements to test than a boolean Y/N then you could also try.
it "should allow valid values" do
%w(item1 item2 item3 item4).each do |v|
should allow_value(v).for(:field)
end
end
it { should_not allow_value("other").for(:role) }
You can also replace the %w() with a constant you have defined in your model so that it tests that only the constant values are allowed.
CONSTANT = %w[item1 item2 item3 item4]
validates :field, :inclusion => CONSTANT
Then the test:
it "should allow valid values" do
Model::CONSTANT.each do |v|
should allow_value(v).for(:field)
end
end
I found one custom shoulda matcher (in one of the projects I was working on) which attempts to coming close to test something like this:
Examples:
it { should validate_inclusion_check_constraint_on :status, :allowed_values => %w(Open Resolved Closed) }
it { should validate_inclusion_check_constraint_on :age, :allowed_values => 0..100 }
The matcher tries to ensure that there is a DB constraint which blows up when it tries to save it.I will attempt to give the essence of the idea. The matches? implementation does something like:
begin
#allowed_values.each do |value|
#subject.send("#{#attribute}=", value)
#subject.save(:validate => false)
end
rescue ::ActiveRecord::StatementInvalid => e
# Returns false if the exception message contains a string matching the error throw by SQL db
end
I guess if we slightly change the above to say #subject.save and let Rails validation blow up, we can return false when the exception string contains something which close matches the real exception error message.
I know this is far from perfect to contributed back to the project, but I guess might not be a bad idea to add into your project as a custom matcher if you really want to test a lot of the :inclusion validation.

Why does this Rails named scope return empty (uninitialized?) objects?

In a Rails app, I have a model, Machine, that contains the following named scope:
named_scope :needs_updates, lambda {
{ :select => self.column_names.collect{|c| "\"machines\".\"#{c}\""}.join(','),
:group => self.column_names.collect{|c| "\"machines\".\"#{c}\""}.join(','),
:joins => 'LEFT JOIN "machine_updates" ON "machine_updates"."machine_id" = "machines"."id"',
:having => ['"machines"."manual_updates" = ? AND "machines"."in_use" = ? AND (MAX("machine_updates"."date") IS NULL OR MAX("machine_updates"."date") < ?)', true, true, UPDATE_THRESHOLD.days.ago]
}
}
This named scope works fine in development mode. In production mode, however, it returns the 2 models as expected, but the models are empty or uninitialized; that is, actual objects are returned (not nil), but all the fields are nil. For example, when inspecting the return value of the named scope in the console, the following is returned:
[#<Machine >, #<Machine >]
But, as you can see, all the fields of the objects returned are set to nil.
The production and development environments are essentially the same. Both are using a SQLite database. Here is the SQL statement that is generated for the query:
SELECT
"machines"."id",
"machines"."machine_name",
"machines"."hostname",
"machines"."mac_address",
"machines"."ip_address",
"machines"."hard_drive",
"machines"."ram",
"machines"."machine_type",
"machines"."use",
"machines"."comments",
"machines"."in_use",
"machines"."model",
"machines"."vendor_id",
"machines"."operating_system_id",
"machines"."location",
"machines"."acquisition_date",
"machines"."rpi_tag",
"machines"."processor",
"machines"."processor_speed",
"machines"."manual_updates",
"machines"."serial_number",
"machines"."owner"
FROM
"machines"
LEFT JOIN
"machine_updates" ON "machine_updates"."machine_id" = "machines"."id"
GROUP BY
"machines"."id",
"machines"."machine_name",
"machines"."hostname",
"machines"."mac_address",
"machines"."ip_address",
"machines"."hard_drive",
"machines"."ram",
"machines"."machine_type",
"machines"."use",
"machines"."comments",
"machines"."in_use",
"machines"."model",
"machines"."vendor_id",
"machines"."operating_system_id",
"machines"."location",
"machines"."acquisition_date",
"machines"."rpi_tag",
"machines"."processor",
"machines"."processor_speed",
"machines"."manual_updates",
"machines"."serial_number",
"machines"."owner"
HAVING
"machines"."manual_updates" = 't'
AND "machines"."in_use" = 't'
AND (MAX("machine_updates"."date") IS NULL
OR MAX("machine_updates"."date") < '2010-03-26 13:46:28')
Any ideas what's going wrong?
This might not be related to what is happening to you, but it sounds similar enough, so here it goes: are you using the rails cache for anything?
I got nearly the same results as you when I tried to cache the results of a query (as explained on railscast #115).
I tracked down the issue to a still open rails bug that makes cached ActiveRecords unusable - you have to choose between not using cached AR or applying a patch and getting memory leaks.
The cache works ok with non-AR objects, so I ended up "translating" the stuff I needed to integers and arrays, and cached that.
Hope this helps!
Seems like the grouping may be causing the problem. Is the data also identical in both dev & production?
Um, I'm not sure you're having the problem you think you're having.
[#<Machine >, #<Machine >]
implies that you have called "inspect" on the array... but not on each of the individual machine-objects inside it. This may be a silly question, but have you actually tried calling inspect on the individual Machine objects returned to really see if they have nil in the columns?
Machine.needs_updates.each do |m|
p m.inspect
end
?
If that does in fact result in nil-column data. My next suggestion is that you copy the generated SQL and go into the standard mysql interface and see what you get when you run that SQL... and then paste it into your question above so we can see.