How to get assigned value when a spec is run in RSpec? - ruby-on-rails

I'm using the FriendlyId gem and it generates a slug when a record is saved. It works great.
I can route to the slug like: places/house-of-dead, perfect. But I'm having a problem when it comes to testing.
I'm using FactoryGirl to stub the parameters that I'm going to create, but I don't know how to get that generated slug to assert if my route redirects to it, my test is below and (???? should be the generated slug).:
context '#create' do
it 'should redirect to place after created' do
place = FactoryGirl.attributes_for(:place)
post :create, { place: FactoryGirl.attributes_for(:place) }
response.should redirect_to places_path(slug: ????)
end
end
My controller is simple:
def create
#place = Place.new(params[:place])
# setting up who owns this place
#place.user = current_user
if #place.save
flash[:success] = "Place created."
redirect_to #place
else
render :new
end
end
As you can see, I use redirect_to #place and it redirects me to `place/:slug', but when it comes to testing that redirect, how do I do it?
Also, is my testing way right/good?
Thanks.

You almost answered yourself:
response.should redirect_to places_path(assigns(:place))
or if you need to use the slug:
response.should redirect_to places_path(slug: assigns(:place).slug)
See https://github.com/rspec/rspec-rails#assigns for more on assigns().
And this line
place = FactoryGirl.attributes_for(:place)
is redundant, as you never use the place variable in the rest of your test.

Related

Create Function Not Redirecting

I am somewhat new to Rails, and I am learning off of a tutorial online. The guy in the videos talked about how you have to have an if statement to decide if the save worked or not.
This is my code:
def create
#quiz = Quiz.new(quiz_params)
if #quiz.save
flash[:notice] = "Your quiz has been created."
redirect_to action: 'index'
else
render('new')
end
end
The quiz_params was defined as such:
params.require(:quiz).permit(:title, :summary, :visible)
For some reason, it refuses to redirect to the index function, deciding to stay on the same page while the URL changes from localhost:3000/quizzes/new to localhost:3000/quizzes.
The guy who taught the tutorial had this code.
def create
#subject = Subject.new(subject_params)
if #subject.save
flash[:notice] = "Subject created succesfully."
redirect_to(subjects_path)
else
render('new')
end
end
The subject_params went as such:
params.require(:subject).permit(:name, :position, :visible)
Other than the wording in the quotes and the name of the model and variables, I am not sure what the difference is. I am being as consistent as I can, so there shouldn't be any difference.
Sorry if the formatting is bad.
You can run rake routes on your command prompt then they see what is the index_path if got to redirect to the home page then write
redirect_to root_path #=> Or root_url
Or if your controller is QuizzesController then your index path is quizzes_path
redirect_to quizzes_path #=> Use instead of redirect_to action: 'index'
Or if you have articles/index then
redirect_to articles_path
Hope to help
Your validation fails and it renders 'new' view. while action remains to create.
If you will see rake routes this route corresponds to localhost:3000/quizzes to create action.
You can refer this answer for details.
you can use byebug to debug the request and see if the code is calling redirect_to or not. it could be an ajax form as #fool said. check the form object in the view if it has remote: true attribute, delete it and try again.
Change below line in controller:
redirect_to action: 'index'
with
redirect_to "/quizzes"
So the code be like:
def create
#quiz = Quiz.new(quiz_params)
if #quiz.save
redirect_to "/quizzes", notice: "Your quiz has been created."
else
render 'new'
end
end
You should tell us Rails and Ruby version. Anyway I am using Rails 5+ and I think the syntax
Render('new')
Is old or deprecated. What I do usually is this.
def create
    plan = Plan.new plan_params
    plan.delivered = 0
    plan.user_id = params['u_id']
    if plan.save
      flash[:OK] = 'Il nuovo piano e\' stato salvato con successo!'
    else
      flash[:err] = 'Siamo spiacenti ma non siamo riusciti a registrare il tuo piano, ricontrolla i dati inseriti!'
      flash[:errors] = plan.errors.messages
    end
    redirect_to plans_users_path(User.find(params['u_id']))
end
So my advice is try to use named paths instead of strings.

Rails Actions for Form Posting

I am using Rails 4 and moved from CakePHP.
I have a User Model and to create a new record it uses two Actions - New and Create.
Now when i want to over ride the default for my app. i would like the users to go to Signup action to create a new user. Now when i have a Server side validation and it fails i am posting the form to lets say "create" action the user is shown in the url
'app.com/user/create' instead of 'app.com/user/signup'
Is there any way to keep the user in the same action instead of have multiple action just to display form and save the form?
# GET /users/new
def new
#user = User.new
end
# POST /users
def create
#user = User.new(user_params)
if #user.save
redirect_to #user, notice: 'User was successfully created.'
else
render :new
end
end
You should simply add a redirect in your create action when the user creation fails.
redirect_to :back, #user
I would not recommend using :back all the time but this is going to be helpful for now as by understanding the scenario you have mentioned.
By default, action new just initialize model with-or-without params. Action create save model to database. app.com/user/create is not RESTful and "Rails Way".
users_path #=> app.com/users
new_user_path #=> app.com/users/new
user_path(:id) #=> app.com/user/:id
edit_user_path(:id) #=> app.com/user/:id/edit
# and so on
In controllers you can define redirections for every action. For example:
def create
if #user.save
redirect_to user_path(#user)
else
redirect_to :back # return to previous page
end
end
More information about routing here: http://guides.rubyonrails.org/routing.html
I would stick with rails conventions but you should be able to do this if you really wanted
Routes.rb
get 'signup', to: 'users#signup'
post 'signup', to: 'users#signup'
Controller
class UsersController < ApplicationController
def signup
if request.get?
#user = User.new
elsif request.post?
#user = User.new(user_params)
if #user.save
redirect_to root_url, notice: 'Signed In'
else
#should just render signup as it's signup action
end
end
end
end

Stop deletion of admin where name like 'string_name'

I'm trying to stop A particular Admin from being removed from the database with ruby on rails
I have tried a few things but heres the code as it stands
Edit 2 changed User.name to #user.name
Model
after_destroy :can_not_destroy_super_admin
private
def can_not_destroy_super_admin
if #user.name == "super admin"
raise "Can't delete this admin"
end
end
I think its a problem with User.name, but I know its seeing this code because I've had errors raising issues with different code I've tried in here.
I'm aware that this is a relatively crude method for stopping deletion of an admin but it's a simple way of getting what I need done.
Any suggestions or help is very much appreciated.
Edit.1
Here is the destroy method
Controller
def destroy
#user = User.find(params[:id])
begin
#user.destroy
flash[:notice] = "User #{#user.name} deleted"
rescue Exception => e
flash[:notice] = e.message
end
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
I'm guessing your destroy action looks something like this?
def destroy
#user = user.find params[:id]
#user.destroy
end
If this is the case, the user you want to check against in your callback is #user.name, not User.name. You want to ensure that the actual user instance you called destroy on is the same one you're checking the name of.
Edit: As determined in the comments, the callback is actually on the model, I misinterpreted as being in the controller. In the model, to reference the objects name, only name is needed, not User.name or #user.name.

Rspec redirect to testing

In my controller when an user creates a new post, he/she is redirected to the page that contains the newly created post. I'm wanting to create a test in rspec to cover this redirect but am having trouble with it. Specifically, I want to know what to write in the refirst_to argument. Here is the controller code below..
def create
#micropost = Micropost.new(params[:micropost])
respond_to do |format|
if #micropost.save
format.html {redirect_to #micropost}
else
format.html {render action: 'edit'}
end
end
end
Here is the rspec test...
before do
#params = FactoryGirl.build(:micropost)
end
it "redirects to index" do
#clearly #params.id doesn't work. its telling me instead of a redirect im getting a
#200
#response.should redirect_to(#params.id)
end
Assuming that #params will create a valid Micropost (otherwise .save will fail and you'll be rendering :edit)...
it "redirects to index on successful save" do
post :create, :micropost => #params.attributes
response.should be_redirect
response.should redirect_to(assigns[:micropost])
end
it "renders :edit on failed save" do
post :create, :micropost => {}
response.should render ... # i don't recall the exact syntax...
end

ID problems with Mongoid and RSpec

So, I've been beating my head against this for a while and just can't make any progress.
I have the following controller action:
def create
#job = Job.new(params[:job])
respond_to do |format|
if #job.save
flash[:notice] = "The Job is ready to be configured"
format.html { redirect_to setup_job_path(#job.id) }
format.json { head :ok }
else
format.html { redirect_to new_job_path, notice: 'There was an error creating the job.' }
format.json { render json: #job.errors, status: :unprocessable_entity }
end
end
end
I am trying to test this action. Here is my test for the redirect on successful creation.
it "redirects to the Job setup" do
job.stub(:id=).with(BSON::ObjectId.new).and_return(job)
job.stub(:save)
post :create
response.should redirect_to(setup_job_path(job.id))
end
job is defined for the whole suite here:
let (:job) { mock_model(Job).as_null_object }
I keep getting the following error:
2) JobsController POST create when the job saves successfully redirects to the Job setup
Failure/Error: response.should redirect_to(setup_job_path(job.id))
Expected response to be a redirect to <http://test.host/jobs/1005/setup> but was a redirect to <http://test.host/jobs/4ea58505d7beba436f000006/setup>
I've tried a few different things but no matter what I try I can't seem to get the proper object ID in my test.
If you stub the :id= you are creating a very weak test. In fact, unless you are super-confident about the Mongoid internals, chances are your tests will break if Mongoid changes the way it generates id. And in fact, it doesn't work.
Also, keep in mind you create a job variable, but you are not passing this variable inside the controller. It means, the :create action will initialize its own job instance at
#job = Job.new(params[:job])
and it will completely ignore your job.
I suggest you to use assigns.
it "redirects to the Job setup" do
post :create
response.should redirect_to(setup_job_path(assigns(:job)))
end

Resources