Render action with parameters after form error - ruby-on-rails

I have basic form that is accessed, for example via: http://url.com/rentals/new/dvd/10.
The problem is when form error happens I can't redirect it to the same page with the same
url segments and show the form error messages.
rentals_controller.rb:
def create
#rental = Rental.new(rental_params)
respond_to do |format|
if #rental.save
format.html { redirect_to #rental, notice: 'Rental was successfully created.' }
format.json { render :show, status: :created, location: #rental }
else
format.html { render :new }
format.json { render json: #rental.errors, status: :unprocessable_entity }
end
end
end
routes.rb
get 'rentals/new/dvd/:dvd_id' => 'rentals#new', as: :new_dvd_rental
I have the following models created:
dvd.rb
class Dvd < ActiveRecord::Base
has_many :rentals
has_many :users, through: :rentals
validates :title, presence: true
validates :year, inclusion: {in: 1900..Time.now.year.to_i}, :presence => {:message => 'Year must be from 1900 till current year.'}
validates :length, inclusion: {in: 1..999}, :presence => {:message => 'DVD length must be in minutes in range 1..999.'}
end
rental.rb
class Rental < ActiveRecord::Base
belongs_to :user
belongs_to :dvd
validates :user_id, presence: true
validates :total_price, presence: true
end
user.rb
class User < ActiveRecord::Base
has_many :rentals
has_many :dvds, through: :rentals
end
As well as rentals_controller.rb:
class RentalsController < ApplicationController
before_action :set_rental, only: [:show, :edit, :update, :destroy]
# GET /rentals
# GET /rentals.json
def index
#rentals = Rental.all
end
# GET /rentals/1
# GET /rentals/1.json
def show
end
# GET /rentals/new
def new
#rental = Rental.new
#users = User.all
#dvd = Dvd.find(params[:dvd_id])
end
# GET /rentals/1/edit
def edit
end
# POST /rentals
# POST /rentals.json
def create
#rental = Rental.new(rental_params)
respond_to do |format|
if #rental.save
format.html { redirect_to #rental, notice: 'Rental was successfully created.' }
format.json { render :show, status: :created, location: #rental }
else
format.html { render :new }
format.json { render json: #rental.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /rentals/1
# PATCH/PUT /rentals/1.json
def update
respond_to do |format|
if #rental.update(rental_params)
format.html { redirect_to #rental, notice: 'Rental was successfully updated.' }
format.json { render :show, status: :ok, location: #rental }
else
format.html { render :edit }
format.json { render json: #rental.errors, status: :unprocessable_entity }
end
end
end
# DELETE /rentals/1
# DELETE /rentals/1.json
def destroy
#rental.destroy
respond_to do |format|
format.html { redirect_to rental_url, notice: 'Rental was successfully deleted.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_rental
#rental = Rental.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def rental_params
params.require(:rental).permit(:dvd_id, :user_id, :rent_date, :return_date, :total_price, :returned)
end
end
I've tried to modify rental controller like this, but still do not know how to pass other segments like new and dvd:
render :action => "new", :dvd_id => params[:dvd_id]
Any ideas?

I think if you draw a more restful route like this
resources :dvds do
resources :rentals
end
you will get the routes like http://url.com/dvd/10/rentals/new
here you will always get dvd_id
and in rentals_controller create method look like
def create
#dvd = Dvd.find(params[:dvd_id])
#rental = Rental.new(rental_params)
respond_to do |format|
if #rental.save
format.html { redirect_to #rental, notice: 'Rental was successfully created.' }
format.json { render :show, status: :created, location: #rental }
else
format.html { render :new }
format.json { render json: #rental.errors, status: :unprocessable_entity }
end
end
end

-- Waiting for #Sanket's ideas
Routes
The issue will almost certainly be with your redirect_to method
The problem is that your controller doesn't know you're using a nested resource, and consequently when you redirect to an object, it will likely just take you to the simplest route it can find
I would try this:
def create
...
else
format.html { render your_nested_resource_path(dvd_id: params[:dvd_id], other: params[:params]) }
...
end
This allows you to send the request to the nested route, which Rails won't route to without support

Related

Rails - NameError - uninitialized constant

I get for what is this error, but I can't see a mistake in my code.
A controller is plural, a model is singular and the table name is plural.
Error on visiting index:
NameError at /admin/custom_communities uninitialized constant
Admin::CustomCommunitiesController::CustomCommunity
Generated controller: (file: controllers/admin/custom_communities_controller.rb)
# frozen_string_literal: true
class Admin::CustomCommunitiesController < Admin::BaseController
before_action :set_custom_community, only: [:show, :edit, :update, :destroy]
def index
#custom_communities = CustomCommunity.page(params[:page])
end
def show; end
def new
#custom_community = CustomCommunity.new
end
def edit; end
def create
#custom_community = CustomCommunity.new(custom_community_params)
respond_to do |format|
if #custom_community.save
format.html { redirect_to #custom_community, notice: "Custom community was successfully created." }
format.json { render :show, status: :created, location: #custom_community }
else
format.html { render :new }
format.json { render json: #custom_community.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #custom_community.update(custom_community_params)
format.html { redirect_to #custom_community, notice: "Custom community was successfully updated." }
format.json { render :show, status: :ok, location: #custom_community }
else
format.html { render :edit }
format.json { render json: #custom_community.errors, status: :unprocessable_entity }
end
end
end
def destroy
#custom_community.destroy
respond_to do |format|
format.html { redirect_to admin_custom_communities_url, notice: "Custom community was successfully destroyed." }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_custom_community
#custom_community = CustomCommunity.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def custom_community_params
params.require(:custom_community).permit(:name, :description, :picture, :should_delete_picture)
end
end
Model: (file: models/custom_community.rb)
# frozen_string_literal: true
class CustomCommunity < ApplicationRecord
end
Migration:
class CreateCustomCommunities < ActiveRecord::Migration[5.2]
def change
create_table :custom_communities do |t|
t.string :name
t.text :description
t.timestamps
end
end
end
Routes:
in admin routes:
resources :custom_communities
I'm sure someone else can explain why, but there are times rails will think that the following class in the index method:
class Admin::CustomCommunitiesController < Admin::BaseController
def index
CustomCommunity.all
end
end
Is referencing a class defined within the Admin::CustomCommunitiesController, i.e. it thinks you're trying to call Admin::CustomCommunitiesController::CustomCommunity.all. To 'unnamespace' the class, try:
# frozen_string_literal: true
class Admin::CustomCommunitiesController < Admin::BaseController
before_action :set_custom_community, only: [:show, :edit, :update, :destroy]
def index
#custom_communities = ::CustomCommunity.page(params[:page])
end
def show; end
def new
#custom_community = ::CustomCommunity.new
end
def edit; end
def create
#custom_community = ::CustomCommunity.new(custom_community_params)
respond_to do |format|
if #custom_community.save
format.html { redirect_to #custom_community, notice: "Custom community was successfully created." }
format.json { render :show, status: :created, location: #custom_community }
else
format.html { render :new }
format.json { render json: #custom_community.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #custom_community.update(custom_community_params)
format.html { redirect_to #custom_community, notice: "Custom community was successfully updated." }
format.json { render :show, status: :ok, location: #custom_community }
else
format.html { render :edit }
format.json { render json: #custom_community.errors, status: :unprocessable_entity }
end
end
end
def destroy
#custom_community.destroy
respond_to do |format|
format.html { redirect_to admin_custom_communities_url, notice: "Custom community was successfully destroyed." }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_custom_community
#custom_community = ::CustomCommunity.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def custom_community_params
params.require(:custom_community).permit(:name, :description, :picture, :should_delete_picture)
end
end
I think that's all of them. Basically switch every CustomCommunity class call to ::CustomCommunity to unnamespace it.

Rails generate records for secondary model on create

I am making a sort of checklist section for my site. I have a model called commission that will contain data about a commissioning task. What I need to do is when a new commission entry is created I need to create a series of about 30 commission tasks that will link to it. A sort of checklist of predefined values for a person to go down through and check. What would be the best way to do this?
Here are my models and controller:
commission.rb
class Commission < ApplicationRecord
has_many :comtasks
belongs_to :project
belongs_to :user
accepts_nested_attributes_for :comtasks, allow_destroy: true
end
comtask.rb
class Comtask < ApplicationRecord
belongs_to :commission
belongs_to :user
end
commissions_controller.rb
class CommissionsController < ApplicationController
before_action :set_commission, only: [:show, :edit, :update, :destroy]
# GET /commissions
# GET /commissions.json
def index
#commissions = Commission.all
end
# GET /commissions/1
# GET /commissions/1.json
def show
end
# GET /commissions/new
def new
#commission = Commission.new
end
# GET /commissions/1/edit
def edit
end
# POST /commissions
# POST /commissions.json
def create
#commission = Commission.new(commission_params)
respond_to do |format|
if #commission.save
format.html { redirect_to #commission, notice: 'Commission was successfully created.' }
format.json { render :show, status: :created, location: #commission }
else
format.html { render :new }
format.json { render json: #commission.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /commissions/1
# PATCH/PUT /commissions/1.json
def update
respond_to do |format|
if #commission.update(commission_params)
format.html { redirect_to #commission, notice: 'Commission was successfully updated.' }
format.json { render :show, status: :ok, location: #commission }
else
format.html { render :edit }
format.json { render json: #commission.errors, status: :unprocessable_entity }
end
end
end
# DELETE /commissions/1
# DELETE /commissions/1.json
def destroy
#commission.destroy
respond_to do |format|
format.html { redirect_to commissions_url, notice: 'Commission was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_commission
#commission = Commission.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def commission_params
params.require(:commission).permit(:project_id, :user_id, :description, :objectname, :location, comtasks_attributes: [:id, :content, :notes])
end
end
Any thoughts or suggestions are appreciated.
below is the idea,
def create
#commission = Commission.create!(commission_params)
# use create not new to generate #commission.id value
# so comtask records can use the id value as reference
create_comtasks_job
# for comtask create I put in other method
respond_to do |format|
if #commission.save
format.html { redirect_to #commission, notice: 'Commission was successfully created.' }
format.json { render :show, status: :created, location: #commission }
else
format.html { render :new }
format.json { render json: #commission.errors, status: :unprocessable_entity }
end
end
end
def create_comtasks_job
# loop 30 tasks / or manual as follow
#commission.comtasks.build(content: 'content1',notes:'notes1')
#commission.comtasks.build(content: 'content2',notes:'notes2')
end
additional code for your model
make sure for your model has relation like sample below
for your model
class Commission < ActiveRecord::Base
has_many :comtasks
end
class Comtask < ActiveRecord::Base
belongs_to :commission
end

Ruby on Rails ActiveResource not saving resource model properly

ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-linux],
Rails 4.2.5
I have two projects. from 1st project i am getting data into second project through api.
User model in 1st project:
class User < ActiveRecord::Base
has_many :cars
end
Car model in 1st project:
class Car < ActiveRecord::Base
belongs_to :user
end
Car model(remote) in 2nd project:
class Car < ActiveResource::Base
self.site = 'https://myeasyb-vssram.c9users.io'
self.format = :json
end
Gpstablecontroller(2nd project):
class GpstablesController < ApplicationController
before_action :set_gpstable, only: [:show, :edit, :update, :destroy]
# GET /gpstables
# GET /gpstables.json
def index
#gpstables = Gpstable.all
end
# GET /gpstables/1
# GET /gpstables/1.json
def show
end
# GET /gpstables/new
def new
#gpstable = Gpstable.new
#gpstables = Gpstable.all
end
# GET /gpstables/1/edit
def edit
#gpstables = Gpstable.all
end
# POST /gpstables
# POST /gpstables.json
def create
#cars = Car.all
#gpstable = Gpstable.new(gpstable_params)
#cars.each do |car|
if #gpstable.car_id == car.id
#car = car
end
end
#car.update_attribute(:gpss, #gpstable.device_id)
respond_to do |format|
if #gpstable.save
format.html { redirect_to gpstables_url, notice: 'Gpstable was successfully created.' }
format.json { render :show, status: :created, location: #gpstable }
else
format.html { render :new }
format.json { render json: #gpstable.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /gpstables/1
# PATCH/PUT /gpstables/1.json
def update
respond_to do |format|
if #gpstable.update(gpstable_params)
Car.all.each do |car|
if #gpstable.car_id == car.id.to_json
#car = car
end
if #gpstable.device_id == car.gpss
car.gpss = 0
car.save!
end
end
#car.gpss = #gpstable.device_id
#car.save!
format.html { redirect_to #gpstable, notice: 'Gpstable was successfully updated.' }
format.json { render :show, status: :ok, location: #gpstable }
else
format.html { render :edit }
format.json { render json: #gpstable.errors, status: :unprocessable_entity }
end
end
end
# DELETE /gpstables/1
# DELETE /gpstables/1.json
def destroy
#cars.each do |car|
if #gpstable.device_id == car.gpss
car.gpss = 0
car.user_id = #gpstable.user_id
car.save
end
end
#gpstable.destroy
respond_to do |format|
format.html { redirect_to gpstables_url, notice: 'Gpstable was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_gpstable
#gpstable = Gpstable.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def gpstable_params
params.require(:gpstable).permit(:device_id, :car_id, :user_id)
end
end
when creating gpstable record i want to update Gpss attribute of car model(remote, calling through api).
it is updating gpss attribute.But it is changing all foriegnkeys including user_id attribute of car model to null.
using devise for users in 1st project.
The problem is i am giving user_id to current user_id in car_params. so i was unable to edit this through resource model. so i changed this to create action.
In my first app i have car controller:
def car_params
params.require(:car).permit(:name, :model, :colour, :ac, :gpss, :wifi, :luggage, :cfare, :card, :crfare, :no, :nos, :user_id, {carpicss: []} ).**merge(user: :current_user)**
end
i removed .merge(user: :current_user) from above code.
and added this in create action
def create
#car = Car.new(car_params)
#car.card=" #{#car.name} : #{#car.no}"
#car.user_id=current_user.id #added here to save current user_id
respond_to do |format|
if #car.save
format.html { redirect_to cars_path, notice: 'Car was successfully created.' }
format.json { render :show, status: :created, location: cars_path }
else
format.html { render :new }
format.json { render json: #car.errors, status: :unprocessable_entity }
end
#car.reload
end
end

What's the correct way of using the accepts_nested_attributes_for and the build methods for updating record in Rails?

I'm using Rails 4.1.4 on a Xubuntu machine. I have a Question model that has many alternativas (possible answers in my language), like this:
# question.rb
class Question < ActiveRecord::Base
has_many :alternativas, dependent: :destroy
validates_presence_of :text
accepts_nested_attributes_for :alternativas, reject_if: proc {|attributes| attributes[:texto].blank? }
end
# alternativa.rb
class Alternativa < ActiveRecord::Base
belongs_to :question
end
Question only has the :text attribute (string), and answer only the :texto attribute (also a string). I can create a question, but when I try to edit it, it edits only the question text, not the answers. New answers are created instead of the old ones being updated.
Also, as the :text field is required, when I leave it blank it redirects to the same page with the error message, but for some weird reason all the answers are doubled (if there is one answer when I submit the form, there will be 2 equal answers when it shows the error message).
So how can I solve this two problems? My guess is that I'm not using the build and the accepts_nested_attributes_for methods correctly, so here is my controller:
class QuestionsController < ApplicationController
before_action :set_question, only: [:show, :edit, :update, :destroy]
before_filter :authorize
before_filter :verify_admin
def index
#questions = Question.all
end
def show
end
def new
#question = Question.new
#question.alternativas.build # I also tried 5.times { #question.alternativas.build } for 5 answers text fields
end
def edit
end
def create
#question = Question.new(question_params)
respond_to do |format|
if #question.save
format.html { redirect_to #question, notice: 'Question was successfully created.' }
format.json { render :show, status: :created, location: #question }
else
format.html { render :new }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #question.update(question_params)
format.html { redirect_to #question, notice: 'Question was successfully updated.' }
format.json { render :show, status: :ok, location: #question }
else
format.html { render :edit }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
def destroy
#question.destroy
respond_to do |format|
format.html { redirect_to questions_url, notice: 'Question was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_question
#question = Question.find(params[:id])
end
def question_params
params.require(:question).permit(:text, { alternativas_attributes: [:texto, :question_id] })
end
end
The problem is with your question_params. It should be like below
def question_params
params.require(:question).permit(:text, alternativas_attributes: [:id, :texto, :question_id])
end

Can't Mass assign attributes with nested form

I have 2 forms, a orders form and a products form. I would like the products form to be under the orders form. I am getting this error: Can't mass-assign protected attributes: products_attributes.
Here is my orders model
class Order < ActiveRecord::Base
attr_accessible :comments, :due_date, :order_type, :print_color, :print_location, :title,
:products
validates :order_type, :due_date, :print_color, :title, :presence => true
validates :title, :uniqueness => true
has_many :products
accepts_nested_attributes_for :products, :allow_destroy => true
end
products model
class Product < ActiveRecord::Base
attr_accessible :quantity
has_one :order
end
orders controller:
>class OrdersController < ApplicationController
# GET /orders
# GET /orders.json
def index
#orders = Order.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #orders }
end
end
# GET /orders/1
# GET /orders/1.json
def show
#order = Order.find(params[:id])
#products = #order.products.find(:all)
respond_to do |format|
format.html # show.html.erb
format.json { render json: #order }
end
end
# GET /orders/new
# GET /orders/new.json
def new
#order = Order.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #order }
end
end
# GET /orders/1/edit
def edit
#order = Order.find(params[:id])
end
# POST /orders
# POST /orders.json
def create
#order = Order.new(params[:order])
respond_to do |format|
if #order.save
format.html { redirect_to #order, notice: 'Order was successfully created.' }
format.json { render json: #order, status: :created, location: #order }
else
format.html { render action: "new" }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
# PUT /orders/1
# PUT /orders/1.json
def update
#order = Order.find(params[:id])
respond_to do |format|
if #order.update_attributes(params[:order])
format.html { redirect_to #order, notice: 'Order was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
# DELETE /orders/1
# DELETE /orders/1.json
def destroy
#order = Order.find(params[:id])
#order.destroy
respond_to do |format|
format.html { redirect_to orders_url }
format.json { head :no_content }
end
end
end
any help would be appreciated! thanks in advance.
Replace:
attr_accessible ..., :products
With:
attr_accessible ..., :products_attributes

Resources