Rails - update/edit check if record exists from controller - validation

I used this page to help me validate if adding a new entry (add a new exercise in my case) which worked great Check if record exists from controller in Rails
But I can't quite seem to get it to work if I'm updating/editing an exercise.
In plain English I'm trying to:
Get current exercise record the user wants to edit(done), user updates the values(done), submits(done), the controller checks the user's input against the db to see if a record already exists with the same name, if it exists error, if not, update.
Thanks.
Here's the part of my controller that I can't quite get going for update:
class ExercisesController < ApplicationController
before_action :authenticate_user!, :except => [:index, :show]
before_filter :set_exercise, only: [:show, :edit, :update, :destroy, :upvote, :downvote]
def new
#exercise = Exercise.new
end
def create
#exercise = current_user.exercises.build(exercise_params)
if Exercise.exists?(name: #exercise.name)
flash.now[:danger] = "Exercise has not been created, duplicate entry"
render :new
elsif #exercise.save
flash[:success] = "Exercise has been created"
redirect_to exercises_path
else
flash.now[:danger] = "Exercise has not been created"
render :new
end
end
def edit
if !current_user.admin?
flash[:danger] = "You are not an admin"
redirect_to root_path
end
end
def update
if !current_user.admin?
flash[:danger] = "You are not an admin"
redirect_to root_path
else
if Exercise.where(:name => #exercise.name).any?
flash.now[:danger] = "Exercise has not been updated, duplicate entry"
render :edit
elsif #exercise.update(exercise_params)
flash[:success] = "Exercise has been updated"
redirect_to #exercise
else
flash.now[:danger] = "Exercise has not been updated"
render :edit
end
end
end
private
def exercise_params
params.require(:exercise).permit(:name, :description, :summary)
end
def set_exercise
#exercise=Exercise.find(params[:id])
end

Found an easier way to make this work. In the model you can specify uniqueness.
class Exercise < ActiveRecord::Base
validates :name, presence: true, :uniqueness => true
so my model looks like this for update:
def update
if !current_user.admin?
flash[:danger] = "You are not an admin"
redirect_to root_path
else
if #exercise.update(exercise_params)
flash[:success] = "Exercise has been updated"
redirect_to #exercise
else
flash.now[:danger] = "Exercise has not been updated"
render :edit
end
end
end

Related

Undefined Method 'add_product ' for model object

I think my error is kind of silly, but it's keeping me stuck. I'm following the Agile Web Development with Rails 4 and developing the app Depot from it. I'm getting a
undefined method `add_product' for #<Cart:0x007f2ee4cfb8f8>
error. My code is as follows,
class LineItemsController < ApplicationController
def create
find_cart
product = Product.find(params[:product_id])
byebug
#line_item = #cart.add_product(product.id) // line with error
#line_item.product = product
respond_to do |format|
if #line_item.save
format.html {redirect_to #line_item.cart,
notice: 'Line Item was succesfully created'}
format.json {render json: #line_item,
status: :created, location: #line_item}
else
format.html {render action: "new"}
format.json {render json: #line_item.errors,
status: "Unprocessable Entry"}
end
end
end
end
Cart.rb
class Cart < ActiveRecord::Base
has_many :line_items, dependent: :destroy
def add_products(product_id)
current_item = line_items.find_by_product_id(product_id)
if current_item
current_item.qunatity += 1
else
current_item = line_items.build(product_id: product_id)
end
current_item
end
end
Also, I want to know, how can a method from different model be directly called into a separate controller ?
The object cart has value, I have debugged to make sure, as well as the error line also has the object present.
Thanks for your help.
I found the mistake, it was a typo I made in Cart.rb. I had named the method add_product's' and was calling add_product in the controller.

Rails 4 ActionController::UrlGenerationError

I'm getting this error ActionController::UrlGenerationError in Manufacturers#index along with No route matches {:action=>"new", :controller=>"cars"} missing required keys: [:manufacturer_id] for the following code. I have looked around and can't find the answer for this one.
cars_controller.rb
class CarsController < ApplicationController
def index
#cars = Car.all
end
def show
#car = Car.find(params[:id])
end
def new
#manufacturer = Manufacturer.find(params[:manufacturer_id])
#car = Car.new(params[:id])
#car.manufacturer = #manufacturer
end
def create
#manufacturer = Manufacturer.find(params[:manufacturer_id])
#car = Car.new(cars_params)
#car.manufacturer = #manufacturer
if #car.save
flash[:notice] = "You have successfully created a car"
redirect_to manufacturer_cars_path
else
render 'new'
end
end
private
def cars_params
params.require(:car).permit(:make, :color, :year, :mileage, :description, :country)
end
end
manufacturers_controller.rb
class ManufacturersController < ApplicationController
def index
#manufacturers = Manufacturer.all
end
def show
#manufacturer = Manufacturer.find(params[:id])
#car = Car.new
end
def new
#manufacturer = Manufacturer.new
end
def create
#manufacturer = Manufacturer.new(manufacturer_params)
if #manufacturer.save
flash[:notice] = "You have successfully created a new manufacturer"
redirect_to root_path(#manufacturer)
else
flash[:alert] = "Please try again"
render :new
end
end
private
def manufacturer_params
params.require(:manufacturer).permit(:name, :country)
end
end
models/car.rb
class Car < ActiveRecord::Base
belongs_to :manufacturer
validates :make, presence: true
validates :color, presence: true
validates :year, presence: true
validates :mileage, presence: true
validates :country, presence: true
end
models/manufacturer.rb
class Manufacturer < ActiveRecord::Base
has_many :cars
validates :name, presence: true
validates :country, presence: true
end
this link works in my cars/index.html.erb <%= link_to "Add Car", new_manufacturer_car_path %> but not in my layouts/application.html.erb or elsewhere. In manufacturers/index.html.erb it asks for the :manufacturer_id so i tried different ways and no luck. perhaps I'm missing something here.
these are my routes
Prefix Verb URI Pattern Controller#Action
root GET / manufacturers#index
manufacturer_cars GET /manufacturers/:manufacturer_id/cars(.:format) cars#index
POST /manufacturers/:manufacturer_id/cars(.:format) cars#create
new_manufacturer_car GET /manufacturers/:manufacturer_id/cars/new(.:format) cars#new
manufacturer_car GET /manufacturers/:manufacturer_id/cars/:id(.:format) cars#show
manufacturers GET /manufacturers(.:format) manufacturers#index
POST /manufacturers(.:format) manufacturers#create
new_manufacturer GET /manufacturers/new(.:format) manufacturers#new
manufacturer GET /manufacturers/:id(.:format) manufacturers#show
I appreciate the help.

How to render the correct page/url with error messages

I have created an app that splits up a Student's Information into multiple forms.
Everything works fine, but when I try to render Form_One after a Validation Error, it does not render the appropriate URL/Page.
EX.
adults/1/students/2/form_one
turns into
adults/1/students/2
I need to render the same url so I can proceed to form_2.
MODELS
class Adult < ActiveRecord::Base
has_many :students
end
class Student < ActiveRecord::Base
belongs_to :adult
validates :firstName, :presence => true,
length: { maximum: 50 }
validates :lastName, :presence => true,
length: { maximum: 50 }
end
CONTROLLER
def update
#adult = Adult.find(params[:adult_id])
#student = Student.find(params[:id])
if #student.update_attributes(student_params)
###IF PASS REDIRECT TO THE NEXT FORM
if URI(request.referer).path == form_one_adult_student_path(#adult, #student)
redirect_to form_two_adult_student_path(#adult, #student)
elsif URI(request.referer).path == form_two_adult_student_path(#adult, #student)
redirect_to form_three_adult_student_path(#adult, #student)
else
redirect_to adult_path(#district, #adult)
end
else
error_messages = #student.errors.messages
#adult = Adult.find(params[:adult_id])
#student = Student.find(params[:id])
#student.errors.messages.merge!(error_messages)
###IF ERROR AND ON FORM_ONE RENDER FORM_ONE
if URI(request.referer).path == form_one_adult_student_path(#adult, #student)
###FOR SOME REASON THIS RENDERS adults/1/students/2
###BUT I NEED IT TO RENDER adults/1/students/2/form_one
render 'form_one'
end
end
end
def form_one
#title = "Student Information"
#adult = Adult.find(params[:adult_id])
#student = Student.find(params[:id])
end
def form_two
#title = "Parent Information"
#adult = Adult.find(params[:adult_id])
#student = Student.find(params[:id])
end
ROUTES
resources :adults do
resources :students do
member do
get :form_one, :form_two
end
end
end
###FOR SOME REASON THIS RENDERS adults/1/students/2
###BUT I NEED IT TO RENDER adults/1/students/2/form_one
render 'form_one'
Try redirect_to instead of render.
Keep in mind the difference between rendering a template, and making an HTTP request. Try pretending you are an HTTP client and think about the requests and responses. Sometimes it helps to look through your server log to see which controller actions happen, in which order. Look for lines like Processing students#update or Redirecting to ....
In the future, you may want to try resourceful routes like #show instead.

How to build a preference record associated with a user in Ruby on Rails?

In Ruby on Rails, when a new user is created I want to automatically create an associated preference record to that user.
This is my controller:
class UsersController < ApplicationController
def create
#user = User.new(params[:user])
if #user.save
#user.build_preference
redirect_to root_path, :notice => "User created."
else
render :new
end
end
end
However, for some reason I can't get this to work. The user gets saved successfully but when I check the database there is no related preference record.
What am I missing here?
Is it better to create the associated record from within the model using :before_create or something?
Thanks for any help.
You need to save:
def create
#user = User.new(params[:user])
if #user.save
pr = #user.build_preference
pr.save!
redirect_to root_path, :notice => "User created."
else
render :new
end
end

App with Accounts and Users - Devise user can't create additional users

Using Rails 3.1.3 with Devise 1.5.3. My app has accounts and users. Each account can have multiple users. A user can have one role, "user" or "account_admin". Devise signup routes to accounts#new. The account and an initial account_admin user are created simultaneously. Got this working as described here (although things have evolved some since then).
An account_admin signs should be able to create additional users in that account. That's where I'm running into trouble: instead of creating new users, it's just redirecting to the user_path (users#show) page with the message "You are already signed in." (user_path is my overridden after_sign_in_path.)
This article asks a similar question. The answer suggests a separate namespace for admins, but since admins are part of my regular app I don't think that applies.
I've defined a complete UsersController. According to the log, GET "/users/new" renders from my "UsersController#new". However POST "/users" is intercepted by Devise and rendered from "Devise::RegistrationsController#create".
config/routes.rb
devise_for :users
devise_scope :user do
get "signup", :to => "accounts#new"
get "signin", :to => "devise/sessions#new"
get "signout", :to => "devise/sessions#destroy"
end
resources :users
resources :accounts
app/controllers/users_controller.rb
class UsersController < ApplicationController
before_filter :authenticate_user!
load_and_authorize_resource # CanCan
...
def new
# CanCan: #user = User.new
end
def create
# CanCan: #user = User.new(params[:user])
#user.skip_confirmation! # confirm immediately--don't require email confirmation
if #user.save
flash[:success] = "User added and activated."
redirect_to users_path # list of all users
else
render 'new'
end
end
...
end
I've tried overriding the Devise controller, thinking I could tell it to use my users#create action if the user is already signed in. The log tells me it is using my controller ("Processing by RegistrationsController#create as HTML"), but it doesn't seem to execute its code. I've commented out my custom actions and just left in the logger lines, but I don't get my logging messages. And in spite of super being commented out, the behavior doesn't change--it still redirects with "You are already signed in."
config/routes.rb
devise_for :users, :controllers => {:registrations => "registrations"}
app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def new
logger.info "Custom RegistrationsController: new"
super
end
def create
logger.info "Custom RegistrationsController: create"
# super unless user_signed_in?
# render "users#create"
end
def update
super
end
end
What am I missing? How can I let the account_admin user create additional users?
The main issue is that Devise was intercepting the POST "/users" (and a few other routes). Found this workaround to allow my Users controller handle those routes: change the devise_for to skip registrations, then add back in the routes for which Devise normally defines aliases:
routes.rb
devise_for :users, :skip => [:registrations]
devise_scope :user do
get "signup", :to => "accounts#new"
get "signin", :to => "devise/sessions#new"
get "signout", :to => "devise/sessions#destroy"
get "cancel_user_registration", :to => "devise/registrations#cancel"
post "user_registration", :to => "users#create"
get "new_user_registration", :to => "accounts#new"
get "edit_user_registration", :to => "users#edit"
end
resources :users
resources :accounts
Never figured out why the Devise controller override wasn't working.
A user on this thread pointed out the devise_invitable gem which might be an interesting alternative.
This is how I ended up getting this to work with my setup (Devise tied to my User model -- no separate Editor/Admin model):
class UsermakersController < ApplicationController
before_action :authenticate_user!
def new
#user = User.new
end
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to users_path, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
else
format.html { render users_path }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
private
def user_params
userParams = params.require(:user).permit(:name, :email)
end
end
From here, when you want to add a new User as another User, simply call the Usermakers#new url in your form, e.g., I have this at the bottom of my Users index page:
<%= link_to 'Add User', new_usermaker_path, id: 'new_user_link' %>
And the Usermakers form looks like:
= simple_form_for #user, url: usermakers_path, html: {multipart: true} do |f|
=f.error_notification errors: true
= f.input :name
= f.input :email
%p
= f.button :submit, 'Create User', class: 'button'
Of course, you'd need to add a dummy new.html.erb file which simply renders _form.html.erb to use this.
Just add the new and create methods to your routes.rb file (whether by resources :usermakers, or more specific routes) and you should be good to go. Hope this helps!

Resources