I am getting this error whenever I try to access the application. The error is about the application controller. This is the error.
Couldn't find all Private::Conversations with 'id': (17, 38) (found 0 results, but was looking for 2).
The error is explained more in the bash as follows
ActiveRecord::RecordNotFound (Couldn't find all Private::Conversations with 'id': (17, 38) (found 0 results, but was looking for 2).):
app/controllers/application_controller.rb:28:in `opened_conversations_windows'
I have tried changing the find method but things do not seem to work with methods such as find_by.
def opened_conversations_windows
if logged_in?
# opened conversations
session[:private_conversations] ||= []
#private_conversations_windows = Private::Conversation.includes(:recipient, :messages)
.find(session[:private_conversations])
else
#private_conversations_windows = []
end
end
I expect that when no conversation is found, the app should render nil conversation windows when a user logs in.
find is designed to raise an error if the record for the given id is not found.
If you do not want to raise an error then you can use find_by when you want to find a single record or return nil when that record doesn't exist. Or you can build a query with where which always returns an array of matching record on an empty array if there any matching records.
You can refactor your method to:
def opened_conversations_windows
if logged_in? && session[:private_conversations]
#private_conversations_windows = Private::Conversation
.includes(:recipient, :messages)
.where(id: session[:private_conversations])
else
#private_conversations_windows = []
end
end
Related
I am trying to write a test suite for a method that sends a POST request with a parameter 'target' that has to be between 0 and 10
My Ruby class:
class ClassName
before_action :must_have_valid_target
def create
target = params[:target]
. . .
end
def must_have_valid_target
return if params.key?(:target)
error_response(422, 'error message')
end
end
My Rspec
it 'cannot create request with negative target' do
post(:create, {target: -1})
assert_response(422) # actual result is: Expected 422, Actual 200
end
I tried:
def must_have_valid_target
valid = params[:target].between?(0,10)
end
but this does not work. How do I check that the symbol has a value between the range so I can give the correct response afterwards?
This is not homework, I am trying to add additional tests to the codebase at my workplace but I am still very new to RSpec and Ruby.
params[:target] is a string, cast to integer prior to the comparison,
def must_have_valid_target
params[:target].present? && params[:target].to_i.between?(0,10)
end
I currently generate a user's profile page using their serial ID, like so:
get '/users/:id' do
#user = User.get(params[:id])
end
This works great, until a number is entered that doesn't exist in the database.
I'm aware I can change User.get to User.get! to return an ObjectNotFoundError error if the record isn't found, but I'm not sure how I can use this to my aid.
I used to use .exists? when using RoR.
Any suggestions?
Thanks in advance!
Edit: I'm going to leave the question unanswered, as I haven't actually found a solution to what I asked in the title; however, I did manage to solve my own problem by checking to see if the :id entered is higher than the amount of users that exist in the database, like so:
if params[:id].to_i > User.count
"This user does not exist."
else
#users_id = User.get(params[:id])
erb(:'users/id')
end
You already have the correct code:
#user = User.get(params[:id])
If no user exists with the given id, then #get will return nil. Then you can just do a conditional:
#user = User.get params[:id]
if #user
# user exists
else
# no user exists
end
This is a very common pattern in Ruby which takes advantage of the "truthiness" of anything other than false or nil. i.e. you can say if 0 or if [] and the condition will evaluate to true
You can recreate a .exists? method:
class User
def self.exists?(id_or_conditions)
if id_or_conditions.is_a? Integer
!! User.get id_or_conditions
else
!! User.first id_or_conditions
end
end
end
#get is similar to #find in rails, except it doesn't raise an error if the record is not found. #first is similar to #find_by in rails.
I am using twitter gem to retrieve tweets for the hash tag. My goal is to retrieve tweets for the last year. I am trying to use :max_id option.
So, I do (twitter is properly configured client):
loop.inject(nil) do |memo|
results = twitter.search "#ruby -rt", (memo ? {max_id: memo - 1} : {})
last = results.inject(nil) do |_, res|
# handle res here, unrelated
res
end
break memo if last.nil? || last.created_at < (Date.today - 365).to_time
last.id
end
The problem is that I receive an empty result set on the subsequent request. That said, the first request returns ≈2K tweets, the second always returns none.
How do I retrieve the statuses from twitter using twitter gem (or using anything else,) by chunks?
Well, it turns out that max_id parameter in call to search is [likely] expected to be a valid tweet id.
By changing
# ⇓⇓⇓⇓ HERE
twitter.search "#ruby -rt", (memo ? {max_id: memo - 1} : {})
to
twitter.search "#ruby -rt", (memo ? {max_id: memo} : {})
I was finally able to retrieve the feeds in the past by chunks.
NB: twitter responds with RateLimit error after each subsequent ≈1.5K statuses returned.
I'm testing out the Fullcontact API to retrieve information about specific people. If the person that I'm looking up with their API doesn't exist in their database it would return a 404 Not found error. I'm trying to get around that by retrieving other usernames, but it's not working. Here's the code:
person = FullContact.person(email: 'wilson#wilsontest.com')
if person.to_i > 400
person = FullContact.person(email: 'wilsonp#gmail.com')
else
person = FullContact.person(email: 'wilson#wilsontest.com')
end
p person
This still displays the 404 Not found when the email isn't found.
If you're using the fullcontact-api-ruby gem, the FullContact.person call should raise a FullContact::NotFound error if the person doesn't exist. You'd need to rescue that error to try something else:
def get_person
emails ||= ['wilson#wilsontest.com', 'wilsonp#gmail.com']
person = FullContact.person(email: emails.shift)
rescue FullContact::NotFound
unless emails.empty?
retry
else
# bottom line
end
end
Note that exceptions are pretty slow in Ruby, and you're also hitting an external API, so be mindful of the response time here.
Here is what I have. And that kind of work.
it "should filter by name" do
users = users.search(:name => "s")
users.each {|u|
u.name.should be_starts_with("s")
}
end
However, the error message returned by rspec is really poor...
expected starts_with?("s") to return true, got false
Is there a way to get a more precise message, showing the element that failed, or at least its index?
In a binary test like this, I would create two users, one that starts with an s, the other without. I would then check that only the expected element was returned.
like
set up a user(:name => "Sam") and user(:name => "Fred")
filtered_users.map(&:name).should =~ ["Sam"]
In the case of failure, you will see something like
expected ["Sam"]
got ["Fred", "Sam"]
This is much more explicit about what you are doing
The reason you are only getting expected true but got false is because the starts_with methods returns true or false and not the actual value.
I'm not sure that this is the best way, but you can output it yourself.
users.each {|u|
p u.name if !u.name.starts_with?("s")
u.name.should be_starts_with("s")
}
Here is the way I used few times in cases like this:
describe 'user' do
before :each do
#users = users.search(:name => "s")
end
#users.each do |u|
it "should filter user with name '#{u.name}'" do
u.name.should be_starts_with("s")
end
end
end
You will have failed user name in you example description.
I found here an interesting extension to the matchers from Rspec concerning each :
http://xtargets.com/2011/08/12/rspec-meta-expectations-over-collections
So I sticked that helper into my spec_helper
RSpec::Matchers.define :each do |meta|
match do |actual|
actual.each_with_index do |i, j|
#elem = j
i.should meta
end
end
failure_message_for_should do |actual|
"at[#{#elem}] #{meta.failure_message_for_should}"
end
that allows me to write
users.should each satisfy {|u| u.name.should be_starts_with 's'}
and the error message is then :
at[1] expected #User to satisfy block
which give me the first index of failure.
With some addition to the error message, I'm sure I could output the details of that object that didn't match, and that seem a pretty good solution.
Any thoughts? I'm not a rubyist, just getting started with rails. Would be nice to get more input from
This should provide you with far better failure messages
it "should filter by name" do
users = users.search(:name => "s")
users.each do |u|
u.name.should match /^s/
end
end
I agree with Corey that calling "be_starts_with" is rough. RSpec expectations are intended to be read fluidly as a sentence. They don't all have to use "be".