How can I improve my "newname" method - ruby-on-rails

I am a student and I got the memo (without explanation) that
my following code is bugged and can be much better. How would you improve my controller#newname method? Thank you for your time!
class ReviewController < ApplicationController
def index
#reviews = Review.all.order(created_at: :desc)
end
def newname
#review = Review.find(params[:id])
if #review.update_attribute(:title, sanitize(params[:title]))
format.json { render json: { status: 200 } }
else
format.json { render json: { status: 500 } }
end
end
end

The biggest flaw is that update_attribute skips all the validations, hence, your else statement will rarely/never be executed. Change it to:
#review.name = sanitize(params[:title])
if #review.save
#...
and it should be much better.

To build upon BroiSatse's answer, I would definitely use save instead of update_attribute. I would also return the errors that occur so the user can parse or show them. If you're on Rails 4, use strong params (declare in a private method in controller)
Rails 3:
def newname
#review = Review.find(params[:id])
#review.title = sanitize(params[:title])
if #review.save
format.json { render json: { status: 200 } }
else
render :json => {:errors => #review.errors.full_messages}, :status => 422
end
end
Rails 4
class ReviewController < ApplicationController
before_action :set_review, only [:newname] #list additional methods as needed...
...
def newname
##review is retrieved from set_review
if #review.update(review_params)
format.json { render json: { status: 200 } }
else
render :json => {:errors => #review.errors.full_messages}, :status => 422
end
end
private
def set_review
#review = Review.find(params[:id])
end
def review_params
params.require(:review).permit(:title)
end
end

I think you could perhaps do something similar to:
class ReviewController < ApplicationController
def index
#reviews = Review.all.order(created_at: :desc)
end
def newname
#review = Review.find(params[:id])
if #review.update(:title => sanitize(params[:title]))
render json: #review
else
render :json => { errors: #review.errors.full_messages }, status: 422
end
end
end
The idea being to stay 'on the rails' and let the conventions do the work for you.
This addresses the
status code
method used to update
errors

Related

How do I pass an object in the rails URL helper

I'm having an issue understanding how to setup the routes in rails to pass an object into the URL helper.
I added a new method add_item
def add_item
#item = Item.create(item_params)
puts #hospital.inspect
puts #item.inspect
#hospital.items << #item
respond_to do |format|
if #hospital.save
format.html { redirect_to hospital_url(#hospital), notice: "Item was added to hospital" }
format.json { render :show, status: :ok, location: #hospital }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #hospital.errors, status: :unprocessable_entity }
end
end
end
I added the corresponding route
resources :hospitals do
member do
post :add_item
end
end
but when I run my test that uses
post add_item_hospital_url(#hospital), params: { item: { item_code: item.item_code, description: item.description, gross_charge: item.gross_charge } }
the #hospital in the test is not nil but on the controller, it is. What am I doing wrong?
My routes seem to be okay.
add_item_hospital POST /hospitals/:id/add_item(.:format)
The instance variable #hospital is nil in the controller because it has not been set. Maybe you could add a before_action to set the value of the instance variable or just add it to the add_item method.
When passing models into the URL helper the id of that object can be found within the params hash
class HospitalsController < ApplicationController
before_action :set_hospital, only: :add_item
def add_item
# ... your code here
end
private
def set_hospital
#hospital = Hospital.find(params[:id])
rescue ActiveRecord::RecordNotFound
# handle exception
end
end

How to fix an undefined method when relationship is established in the controller and table?

I'm trying to build a simple rails app. I have generated a model called cities and added a migration for city_name. Leveraging a form, I was to create my first city. However, when I go show.html.erb - I'm not able see my city name. Instead I'm prompted with an error "undefined method `city_name' for nil:NilClass"
I have pasted all my relevant code below. Any help would be greatly appreciated.
Cities Controller
class CitiesController < ApplicationController
def index
#cities = City.all
end
def new
#city = City.new
end
def show
end
def create
#city = City.new(city_params)
respond_to do |format|
if #city.save
format.html { redirect_to #city, notice: 'City was successfully created.' }
format.json { render :show, status: :created, location: #city }
else
format.html { render :new }
format.json { render json: #city.errors, status: :unprocessable_entity }
end
end
end
private
def city_params
params.require(:city).permit(:city_name)
end
end
Show.html.erb
<p>
<strong>
<%= #city.city_name %>
</strong>
</p>
<%= link_to 'Back', cities_path %>
Cities Model
class City < ApplicationRecord
end
I figured out what the mistake was, the issue is in the controller. I need to set up a before action and write out a method that would search for the param id of the specific city. My controller code is listed below for easy reference in case anyone else struggles with this.
class CitiesController < ApplicationController
before_action :set_city, only: [:show]
def index
#cities = City.all
end
def new
#city = City.new
end
def show
end
def create
#city = City.new(city_params)
respond_to do |format|
if #city.save
format.html { redirect_to #city, notice: 'City was successfully created.' }
format.json { render :show, status: :created, location: #city }
else
format.html { render :new }
format.json { render json: #city.errors, status: :unprocessable_entity }
end
end
end
private
def set_city
#city = City.find(params[:id])
end
def city_params
params.require(:city).permit(:city_name)
end
end
If you build a simple ruby on rails then here's show def
def show
#service_order = ServiceOrder.find(params[:id])
end
end

Can't create data rails, no method error

I'm implementing a website using Ruby on Rails. I have a trouble which I cannot create a new data and save to my model. The error i got is this which the error pointed to the #vpermits = current_user.vpermits.build(vpermit_params). Anyone have idea on what I have i done wrong?
NoMethodError in VisitorPermitsController#create
undefined method `vpermits' for #<User:0x9b7b478>
def create
#vpermits = current_user.vpermits.build(vpermit_params)
if #vpermits.save
redirect_to #vpermits
else
This is my visitor_permits_controller.rb
class VisitorPermitsController < ApplicationController
before_action :set_vpermit, only: [:destroy]
def index
#vpermits = VisitorPermit.where(:user_id => current_user.id)
end
def new
#vpermits = VisitorPermit.new
end
def create
#vpermits = current_user.vpermits.build(vpermit_params)
if #vpermits.save
redirect_to #vpermits
else
render 'new'
end
end
def destroy
VisitorPermit.destroy_all(user_id: current_user)
respond_to do |format|
format.html { redirect_to root_path, notice: 'Permit was successfully canceled.' }
format.json { head :no_content }
end
end
def show
#vpermits = VisitorPermit.find(params[:id])
end
def update
#vpermits = VisitorPermit.where(user_id: current_user).take
respond_to do |format|
if #vpermits.update(vpermit_params)
format.html { redirect_to root_path}
flash[:success] = "Permit successfully updated"
format.json { render :show, status: :ok, location: #user }
else
format.html { render :edit }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
def edit
#vpermits = VisitorPermit.find(params[:id])
end
private
# Use callbacks to share common setup or constraints between actions.
def set_vpermit
#vpermits = VisitorPermit.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def vpermit_params
params.require(:visitor_permit).permit(:vehicle_type, :name, :department, :carplate, :duration, :permitstart, :permitend)
end
end
From your code you might have association(has_many) between User and VistorPermit models. And you gave your model name as VistorPermit. So the
line of code for buliding should be like this:
#vpermits = current_user.vistor_permits.build(vpermit_params)

NoMethodError : undefined method `find' for nil:NilClass

I want show a daycare details on show page but I got this error
NoMethodError : undefined method `find' for nil:NilClass
from daycare controller file and i'm not get any idea. I have mentioned below that error line.
This is my Controller file
class DayCaresController < ApplicationController
before_filter :authenticate_user!
before_action :set_day_care, only: [:show, :edit, :update, :destroy]
# GET /day_cares
# GET /day_cares.json
def index
#day_cares = DayCare.all
end
# GET /day_cares/1
# GET /day_cares/1.json
def show
end
# GET /day_cares/new
def new
#day_care = DayCare.new
end
# GET /day_cares/1/edit
def edit
end
# POST /day_cares
# POST /day_cares.json
def create
#day_care = current_user.build_day_care(day_care_params)
respond_to do |format|
if #day_care.save
UserMailer.welcome_email(#user).deliver
format.html { redirect_to #day_care, :gflash => { :success => 'Day care was successfully created.'} }
format.json { render :show, status: :created, location: #day_care }
else
format.html { render :new }
format.json { render json: #day_care.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /day_cares/1
# PATCH/PUT /day_cares/1.json
def update
respond_to do |format|
if #day_care.update(day_care_params)
format.html { redirect_to #day_care, :gflash => { :success => 'Day care was successfully updated.'} }
format.json { render :show, status: :ok, location: #day_care }
else
format.html { render :edit }
format.json { render json: #day_care.errors, status: :unprocessable_entity }
end
end
end
# DELETE /day_cares/1
# DELETE /day_cares/1.json
def destroy
#day_care.destroy
respond_to do |format|
format.html { redirect_to day_cares_url, :gflash => { :success => 'Day care was successfully destroyed.'} }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions
def set_day_care
#day_care = current_user.day_care.find(params[:id]) # => **I got error this line**
end
# Never trust parameters from the scary internet, only allow the white list through.
def day_care_params
params.require(:day_care).permit(:name, :address, :office_phone, :cell_phone, :logo, :website, :user_id)
end
def dashboard
end
def profile
end
end
If user has_many: day_cares then use this name instead of day_care:
#day_care = current_user.day_cares.where(id: params[:id]).take
or probably as you wrote:
#day_care = current_user.day_cares.find(params[:id])
But with arrays instead of single instance (day_cares).
Also you can use just:
#day_care = DayCare.find(params[:id])
If you search by id. Or if you need to check that it's users day_care:
#day_care = DayCare.where(id: params[:id], user: current_user).take
current_user.day_care.find is not available, because you can only perform queries on plural associations. So given that the model associations are setup correctly as:
class User < ActiveRecord:Base
has_many :day_cares
...
end
the solution is probably just to resolve the spelling error from
`current_user.day_care.find` #wrong!
to
`current_user.day_cares.find` #right!

How do you render hashes as JSON in Rails 3

I found how to render ActiveRecord objects in Rails 3, however I cannot figure out how to render any custom objects. I am writing an app without ActiveRecord. I tried doing something like this:
class AppController < ApplicationController
respond_to :json
...
def start
app.start
format.json { render :json => {'ok'=>true} }
end
end
When you specify a respond_to, then in your actions you would make a matching respond_with:
class AppControlls < ApplicationController
respond_to :json
def index
hash = { :ok => true }
respond_with(hash)
end
end
It looks like you're conflating the old respond_to do |format| style blocks with the new respond_to, respond_with syntax. This edgerails.info post explains it nicely.
class AppController < ApplicationController
respond_to :json
def index
hash = { :ok => true }
respond_with(hash.as_json)
end
end
You should never use to_json to create a representation, only to consume the representation.
format.json { render json: { ok: true } } should work
This was very close. However, it does not automatically convert the hash to json. This was the final result:
class AppControlls < ApplicationController
respond_to :json
def start
app.start
respond_with( { :ok => true }.to_json )
end
end
Thanks for the help.
For those getting a NoMethodError, try this:
class AppController < ApplicationController
respond_to :json
...
def start
app.start
render json: { :ok => true }
end
end

Resources