I am very new to rails and I am writing test cases for my rails application.
Suppose I have a code like this -
class EmailController < ApplicationController
def new
render :layout => false
end
def create
begin
process_email = ProcessEmail.new(params)
process_email.perform
rescue EmailHelper::HtmlSanitizerTimeoutError, EmailHelper::NokogiriTimeoutError => e
NewRelic::Agent.notice_error(e, account_id: Account.current.id, subject: params[:subject])
process_email.mark_email_on_timeout
end
render layout: 'email'
end
def update
----
end
I have written test cases for create and update. But how do I write
test cases that will execute the rescue part??
This is my db
(class abc < ActiveRecord::Base)
this is my controller class
(class abcsController < ApiApplicationController).
I have written minitest like this `
def test_raise_exception
params = {"a":"b"}
item = abc.new(params)
raises_exception = -> { raise ArgumentError.new }
item.stub :create, raises_exception do
assert_raises(ArgumentError) { post :create }
end
end`
This is error which is coming -
NameError: NameError: undefined method create' for class
Related
So, I've only been doing Ruby for a couple of days. Any tips would be appreciated it.
variable.rb
class Variable < ApplicationRecord
def some_attribute=(value)
#do something with the vlue
end
end
X_Controller.rb
class XController < ApplicationController
def do_something
variable = Variable.instance_with_id(params[:id])
variable.some_attribute = some_new_value
redirect_to(some_url)
end
end
x_controller_spec.rb
describe '#do_something' do
before do
allow(Variable).to receive(:instance_with_id) # Works fine
allow_any_instance_of(Variable).to receive(:some_attribute)
post :do_something, :params => { id: 'uuid' }, :format => :json
end
it {
expect(variable).to have_received(:some_attribute)
}
end
You probably want this:
let(:variable) { instance_double("Variable") }
before do
allow(Variable).to receive(:instance_with_id).and_return(variable)
allow(variable).to receive(:some_attribute=)
# ...
end
Because instance_with_id should return something. And then you want to allow calling some_attribute=(note the =) on that instance.
The following action
def send(server=1)
#messagelog = Messagelog.new(server_id: params[:server], struttura_id: params[:struttura], user_id: params[:user], chat_id: params[:chat], methodtype_id: params[:methodtype], payload: params[:payload])
#messagelog.save
bot = Telegram.bot
case params[:methodtype]
when 1
result = bot.send_message(chat_id: params[:chat], text: params[:payload])
when 2
result = bot.send_photo(chat_id: params[:chat], photo: params[:payload])
when 3
result = bot.send_document(chat_id: params[:chat], document: params[:payload])
else
end
#messagelog.update_attributes(result: result.to_json)
rescue StandardError => msg
end
is invoked via an API and runs 5 times, rescued or not. Its route is:
namespace :api do
namespace :v1 do
post 'send', to: 'messages#send', defaults: { format: :json }
The class class Api::V1::MessagesController < Api::V1::ApibaseController does not invoke before_actions, however it inherits
class Api::V1::ApibaseController < ApplicationController
before_action :access_control
def access_control
authenticate_or_request_with_http_token do |token, options|
#server = Server.where('apikey = ?', token).first
end
end
Where is this multiplication of actions originating from? The only hiccup from the logs is a statment that:
No template found for Api::V1::MessagesController#send, rendering head :no_content
If the param are hard-wired to the action, this is also generated, but only one action occurs. Rails 5.2.4
How can this be resolved?
I'm trying to create a mailer and allow a status to be changed to pending upon creation. So I have the following in my controller:
class Api::UserTrainingResourcesController < Api::BaseController
respond_to :html, :json
def create
#user_training_resource = UserTrainingResource::Create.call(user_training_resource_params)
respond_with(#user_training_resource)
end
def destroy
#user_training_resource = UserTrainingResource.find_by(params[:id])
#user_training_resource.destroy
end
private
def user_training_resource_params
params.require(:user_training_resources).permit(:training_resources_id, :status).merge(spud_user_id: current_user_id)
end
end
Then in my Operations I have the following create:
class UserTrainingResource
class Create < Operation
def call(params)
params[:status] = :pending
training_resource = UserTrainingResource.new(params)
UserTrainingResourceMailer.requested(training_resource).deliver_later if training_resource.save
training_resource
end
end
end
My model has:
class UserTrainingResource < ApplicationRecord
belongs_to :user
belongs_to :training_resource
enum status: [:pending, :confirmed, :rejected], _prefix: :status
scope :employee, -> { where.not(status: ['rejected']) }
scope :hr, -> { where(status: SameScope::HR) }
module SameScope
HR = ['pending', 'confirmed', 'rejected'].freeze
end
def view_user_training_resource_request?(user)
return true if user.human_resources && SameScope::HR.include?(status)
false
end
def change_status?(user, status)
return true if user.human_resources && SameScope::HR.include?(status)
false
end
end
Then in my test I have:
require 'rails_helper'
RSpec.describe UserTrainingResource::Create do
let(:params) { attributes_for(:user_training_resource).merge(user_id: create(:user).id) }
describe '#call' do
it 'queues a mailer' do
ut = UserTrainingResource::Create.call(params)
expect(UserTrainingResourceMailer).to send_mail(:requested)
expect(ut.status).to eq('pending')
end
end
end
So this ends up with a Failure/Error: expect(ut.status).to eq('pending') Expect: "pending", got" nil. (compared using ==)
I thought the issue was that pending was not saving to the db but that's because I had status present as a string not an integer when using enum in the model. But it's still getting nil.
Edit:
After noticing that I had status using string I went ahead and added in a migration file to change it to integer. Test failed with the same issue. Tried to rollback my test environment, failed. Did a rake db:reset. Re-added in data in both development and test. Still getting the issue of essentially:
Failure/Error: expect(ut.status).to eq('pending')
expected: "pending"
got: nil
(compared using ==)
I'm using RSpec and FactoryGirl for testing my models and I'm stuck at "highest_priority" method which can't be seen by RSpec for some reason.
Here's the method itself:
models/task.rb
class Task < ActiveRecord::Base
#some stuff
def self.highest_priority
p = Task.order(:priority).last.try(:priority)
p ? p + 1 : 1
end
end
And when I run task_spec.rb
require 'spec_helper'
describe Task do
it "returns highest priority" do
last_task = FactoryGirl.build(:task, priority: "5")
last_task.highest_priority
expect(last_task(:priority)).to eq("6")
end
end
I get the following error:
When I'm calling this method in my controller like this
def create
#task = current_user.tasks.build(task_params)
#task.highest_priority
#task.complete = false
respond_to do |format|
if #task.save
format.js
else
format.js
end
end
end
And the method looks like
def highest_priority
self.maximum(:priority).to_i + 1
end
I'm getting
First of all, you better use ActiveRecord's maximum instead of ordering and then picking one, you'll avoid the instance initialization and get a number directly from the query
Task.maximum(:priority)
this could be put in a class method like this
def self.maximum_priority
Task.maximum(:priority) || 0 # fall back to zero if no maximum exists
end
Then for the second half which is updating the method, i would create an instance method for that, and using the class method
def set_maximum_priority
self.priority = self.class.maximum_priority + 1
self
end
Note that I returned self at the end for chainability
Then your action would become something like this
def create
#task = current_user.tasks.build(task_params).set_maximum_priority
#task.complete = false
...
end
You need to create the method as an instance method of Task model. Like below :
class Task < ActiveRecord::Base
#some stuff
def highest_priority
p = Task.order(:priority).last.try(:priority)
p ? p + 1 : 1
end
end
Why is this undefined? Does it have something to do with the #current_user?
I'm trying to create tasks for my challenges. And the created task should get /achievements. However, I get a GET 500 error.
This is the error I get:
NoMethodError at /achievements
==============================
> undefined method `achievements' for #<User:0x00000105140dd8>
app/controllers/achievements_controller.rb, line 5
--------------------------------------------------
``` ruby
1 class AchievementsController < ApplicationController
2
3
4 def index
> 5 #achievements = #current_user.achievements
6 render :json => #achievements
7 end
8
9 def new 10 #achievement = Achievement.new
This is my code in my controller
class AchievementsController < ApplicationController
def index
#achievements = #current_user.achievements
render :json => #achievements
end
def new
#achievement = Achievement.new
render :json => #achievement
end
#create a new achievment and add it to the current user
#check then set the acheivments pub challenge id to the current pub challenge
def create
#achievement = Achievement.new achievement_params
#achievement.user = #current_user.id
#achievement.pub_challenge = params[:id]
if #achievement.save
# render :json => #achievement #{ status: 'ok'}
else
render :json => {:errors => #achievement.errors}
end
end
def show
#achievement = Achievement.find params[:id]
render :json => #achievement
end
def destroy
#achievement = Achievement.find params[:id]
#achievement.destroy
end
private
def achievement_params
params.require(:achievement).permit(:pub_challenges)
end
end
You are missing the has_many :achievements relation in your User model.
You'll need to create the ActiveRecord associations you require:
#app/models/user.rb
class User < ActiveRecord::Base
has_many :achievements
end
#app/models/achievement.rb
class Achievement < ActiveRecord::Base
belongs_to :user
end
This will give you the ability to call the achievements method on any User objects you have.
Error
The error you have is described as such:
undefined method `achievements' for #<User:0x00000105140dd8>
This basically means that you're trying to call an undefined method on a User object. Might sound simple, but really, most people don't understand it.
To explain properly, you have to remember that Rails, by virtue of being built on Ruby is object orientated. This means that everything you do in Rails should be structured around objects - which are defined in your Models:
This means that each time you call an object, you're actually above to invoke a series of "methods" which will give you the ability to either manipulate the object itself, or any of the associated functionality it has.
The problem you have is that your User object doesn't have the achievements method. Whilst you could simply do the following to fix the issue, because it's Rails, you'll need to populate the record with associative data:
#app/models/user.rb
class User < ActiveRecord::Base
has_many :achievements #-> what you need
def achievements
#this will also fix the error you see, although it's fundamentally incorrect
end
end
Something that helped me with this type of error was that the database table was missing the relevant column. Adding the required column to the database fixed the issue.