Rails form with nested attributes (accepts_nested_attributes_for) - ruby-on-rails

I have this one to many relationship:
class Programa < ActiveRecord::Base
attr_accessible :descripcion, :nombre, :roles_attributes
has_many :roles, :dependent => :restrict
accepts_nested_attributes_for :roles
...
end
class Role < ActiveRecord::Base
attr_accessible :description, :name, :programa_id
belongs_to :programa
...
end
It works in rails console:
> params = { programa: { nombre: 'nuevo', roles_attributes: [ {name: 'role1'}, {name: 'role2'}] }}
> p = Programa.create(params[:programa])
> p
=> #<Programa id: 7, nombre: "nuevo", descripcion: nil, created_at: "2013-10-09 14:07:46", updated_at: "2013-10-09 14:07:46">
> p.roles
=> [#<Role id: 15, name: "role1", description: nil, created_at: "2013-10-09 14:07:46", updated_at: "2013-10-09 14:07:46", programa_id: 7>, #<Role id: 16, name: "role2", description: nil, created_at: "2013-10-09 14:07:46", updated_at: "2013-10-09 14:07:46", programa_id: 7>]
But I can not make it work in the app/views/programas/_form:
<%= form_for(#programa) do |f| %>
<%= render 'shared/form_error_messages', object: f.object %>
<div class="field">
<%= f.label :nombre %>
<%= f.text_field :nombre %>
</div>
<div class="field">
<%= f.label :descripcion %>
<%= f.text_field :descripcion %>
</div>
<% f.fields_for :roles do |builder| %>
<div class="field">
<%= builder.label :name %>
<%= builder.text_field :name %>
</div>
<div class="field">
<%= builder.label :description %>
<%= builder.text_field :description %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Is there anything else that I have to add or remove to make my form shows the roles nested attributes?
This is my the controller for programas:
class ProgramasController < ApplicationController
# GET /programas
# GET /programas.json
def index
#programas = Programa.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #programas }
end
end
# GET /programas/1
# GET /programas/1.json
def show
#programa = Programa.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #programa }
end
end
# GET /programas/new
# GET /programas/new.json
def new
#programa = Programa.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #programa }
end
end
# GET /programas/1/edit
def edit
#programa = Programa.find(params[:id])
end
# POST /programas
# POST /programas.json
def create
#programa = Programa.new(params[:programa])
respond_to do |format|
if #programa.save
format.html { redirect_to #programa, notice: 'Programa was successfully created.' }
format.json { render json: #programa, status: :created, location: #programa }
else
format.html { render action: "new" }
format.json { render json: #programa.errors, status: :unprocessable_entity }
end
end
end
# PUT /programas/1
# PUT /programas/1.json
def update
#programa = Programa.find(params[:id])
respond_to do |format|
if #programa.update_attributes(params[:programa])
format.html { redirect_to #programa, notice: 'Programa was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #programa.errors, status: :unprocessable_entity }
end
end
end
# DELETE /programas/1
# DELETE /programas/1.json
def destroy
#programa = Programa.find(params[:id])
#programa.destroy
respond_to do |format|
format.html { redirect_to programas_url }
format.json { head :no_content }
end
end
end
I just want the nested attributes to be shown in the edit and show actions only.

The form for the nested attributes will only show if there is actually data to show, ie. if your Programa instance has one or more Roles associated with it.
This can be as simple as #programa.roles.build in your controller, before rendering the form, to add a new Role. Any existing roles will be rendered.
edit: You also need to actually render the form, ie. <%= f.fields_for (note missing =).

Related

Rails Enum '0' is not a valid incomeType

I have a Ruby on Rails app that handles a users income, decides if it is an allowance or an income and applies the appropriate tax rates. I have included some enums to do basic functions as outlined below.
When I go to update from the default I hit the issue '1' is not a valid incomeType.
Below you can see the set up including model, controller and form.
model :
class Income < ApplicationRecord
enum incomeType: {income: 0, allowance: 1 }
enum taxed: {yes: 0, no: 1 }
belongs_to :user
end
controller:
class IncomesController < ApplicationController
before_action :set_income, only: [:show, :edit, :update, :destroy]
# GET /incomes
# GET /incomes.json
def index
#incomes = current_user.incomes.all
end
# GET /incomes/1
# GET /incomes/1.json
def show
end
# GET /incomes/new
def new
#income = current_user.incomes.build
end
# GET /incomes/1/edit
def edit
end
# POST /incomes
# POST /incomes.json
def create
#income = current_user.incomes.new(income_params)
respond_to do |format|
if #income.save
format.html { redirect_to #income, notice: 'Income was successfully created.' }
format.json { render :show, status: :created, location: #income }
else
format.html { render :new }
format.json { render json: #income.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /incomes/1
# PATCH/PUT /incomes/1.json
def update
respond_to do |format|
if #income.update(income_params)
format.html { redirect_to #income, notice: 'Income was successfully updated.' }
format.json { render :show, status: :ok, location: #income }
else
format.html { render :edit }
format.json { render json: #income.errors, status: :unprocessable_entity }
end
end
end
# DELETE /incomes/1
# DELETE /incomes/1.json
def destroy
#income.destroy
respond_to do |format|
format.html { redirect_to incomes_url, notice: 'Income was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_income
#income = Income.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def income_params
params.require(:income).permit(:amount, :frequency, :user_id, :incomeType, :country, :taxed)
end
end
Form :
<%= form_with(model: income, local: true) do |form| %>
<% if income.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(income.errors.count, "error") %> prohibited this income from being saved:</h2>
<ul>
<% income.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :amount %>
<%= form.text_field :amount, id: :income_amount %>
</div>
<div class="field">
<%= form.label :frequency %>
<%= form.select :frequency, options_for_select([['Weekly', '52'], ['Fortnightly', '26'], ['Monthly', '12'], ['Bi-Monthly', '6'], ['Annually', '1']]), id: :income_frequency %>
</div>
<div class="field">
<%= form.label :incomeType %>
<%= form.select :incomeType, options_for_select([['Income', '0'], ['Allowance', '1']]), id: :incomeType %>
</div>
<div class="field">
<%= form.label :taxed %>
<%= form.select :taxed, options_for_select([['Yes', '0'], ['No', '1']]), id: :taxed %>ra
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
Hopefully you can point me in the right direct.
{"utf8"=>"✓",
"_method"=>"patch",
"authenticity_token"=>"HUTd5Bav9eAfWPTFFyqeD69aL4mIgZodIuL1+9eL0zIhN+SjDwAMcD7AzKEuhm6az4iALBSrDUXd/1vVfN77SQ==",
"income"=>{"amount"=>"102000.0", "frequency"=>"1", "incomeType"=>"0", "taxed"=>"1"},
"commit"=>"Update Income",
"id"=>"4f9fc439-4578-487e-bc5d-02cf0cd9aaa3"}
Thanks in advance for your help
Yes it is because enum needs key not the value and you are sending value not the key so in your case enum is trying to find '0' as one key which is not present. So just change your form slightly
<%= form.select :incomeType, options_for_select([['Income', 'income'], ['Allowance', 'allowance']]), id: :incomeType %>
PS : change form for taxed as well.
Hope this will help

Rails - Simple Form - Cocoon gem - Date picker works in edit but not in create

I am using rails 5 with simple form and cocoon gem.
I have am model called Tenor.
The tenor form fields are nested inside parent models. The attributes in the tenor model are:
<div class="nested-fields">
<div class="form-inputs">
<div class="row">
<div class="col-md-4">
<%= f.input :express_interest, :as => :date_picker, :label => 'When are expressions of interest due?' %>
</div>
<div class="col-md-4">
<%= f.input :commencement, :as => :date_picker, :label => 'Commencement date' %>
</div>
<div class="col-md-4">
<%= f.input :expiry, :as => :date_picker, :label => 'Expiry date' %>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6" style="margin-bottom: 50px">
<%= link_to_remove_association 'Remove schedule', f %>
</div>
</div>
</div>
The tenor form fields are rendered inside another form, by this link:
<%= f.simple_fields_for :tenor do |f| %>
<%= f.error_notification %>
<%= render 'tenors/tenor_fields', f: f %>
<% end %>
<%# unless #bip.tenor.present? %>
<%= link_to_add_association 'Add key dates', f, :tenor, partial: 'tenors/tenor_fields', force_non_association_create: true %>
<%# end %>
There is a one to one association between bip and tenor.
The date_picker works fine when I edit an existing record. I can click on the calendar icon and it reveals the calendar.
However, when I try to create a new record, the date_picker doesn't do anything. I click the calendar icon and nothing happens. There are no console errors showing in the chrome inspector. I can type date in manually in the input box, but I can't select a date from the calendar. I can submit the form with manually inserted dates, but the date particulars do not save to the database (the records remain 'nil').
My inputs/date_picker_input.rb has
class DatePickerInput < SimpleForm::Inputs::StringInput
def input(wrapper_options)
set_html_options
set_value_html_option
template.content_tag :div, class: 'input-group date datetimepicker' do
input = super(wrapper_options) # leave StringInput do the real rendering
input + input_button
end
end
def input_html_classes
super.push '' # 'form-control'
end
private
def input_button
template.content_tag :span, class: 'input-group-btn' do
template.content_tag :button, class: 'btn btn-default', type: 'button' do
template.content_tag :span, '', class: 'fa fa-calendar'
end
end
end
def set_html_options
input_html_options[:type] = 'text'
input_html_options[:data] ||= {}
input_html_options[:data].merge!(date_options: date_options)
end
def set_value_html_option
return unless value.present?
input_html_options[:value] ||= I18n.localize(value, format: display_pattern)
end
def value
object.send(attribute_name) if object.respond_to? attribute_name
end
def display_pattern
I18n.t('datepicker.dformat', default: '%d/%m/%Y')
end
def picker_pattern
I18n.t('datepicker.pformat', default: 'DD/MM/YYYY')
end
def date_view_header_format
I18n.t('dayViewHeaderFormat', default: 'MMMM YYYY')
end
def date_options_base
{
locale: I18n.locale.to_s,
format: picker_pattern,
dayViewHeaderFormat: date_view_header_format
}
end
def date_options
custom_options = input_html_options[:data][:date_options] || {}
date_options_base.merge!(custom_options)
end
end
Can anyone think of why the date_picker would work just fine if I am editing an existing record but will not work if I am trying to create a new record?
Create actions in controllers
Organisation
def create
#organisation = Organisation.new(organisation_params)
respond_to do |format|
if #organisation.save
format.html { redirect_to #organisation, notice: 'Organisation was successfully created.' }
format.json { render :show, status: :created, location: #organisation }
else
format.html { render :new }
format.json { render json: #organisation.errors, status: :unprocessable_entity }
end
end
end
Bip
def create
#bip = Package::Bip.new(bip_params)
# authorize #bip
respond_to do |format|
if #bip.save
format.html { redirect_to #bip }
format.json { render :show, status: :created, location: #bip }
else
format.html { render :new }
format.json { render json: #bip.errors, status: :unprocessable_entity }
end
end
end
Tenor
def create
#tenor = Tenor.new(tenor_params)
# authorize #tenor
respond_to do |format|
if #tenor.save
format.html { redirect_to #tenor }
format.json { render :show, status: :created, location: #tenor }
else
format.html { render :new }
format.json { render json: #tenor.errors, status: :unprocessable_entity }
end
end
end
New action
Organisation
def new
#organisation = Organisation.new
#organisation.bips
# #organisation.bips.build_tenor
end
Bips
def new
#bip = Package::Bip.new
# authorize #bip
end
Tenor
def new
#tenor = Tenor.new
# authorize #tenor
end

Rails: One_to_one relationship and form_for sending format instead of ID and params

I'm pretty new to rails and I'm having a bit of a though time to register my employeur.
Here are my routes:
resources :users do
resource :prestataire
resource :employeur
end
I have a has_one relationship between my employeur and user resources:
class User < ActiveRecord::Base
has_one :prestataire
has_one :employeur
has_secure_password
end
class Employeur < ActiveRecord::Base
belongs_to :user
validates :siren, :societe, :code_postal, presence: true
end
And here's where I think the issue is:
<%= form_for [#user,#employeur], url: user_employeur_path(#user) do |f| %>
<% if #employeur.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#employeur.errors.count, "error") %> prohibited this employeur from being saved:</h2>
<ul>
<% #employeur.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :siren, 'Siren: ' %><br>
<%= f.text_field :siren %>
</div>
.
.
.
<div class="actions">
<%= f.submit %>
</div>
<% end %>
When I fill in this issue, I'm redirected to /users/193/employeur.84 and I get this error: Couldn't find Employeur without an ID
Those are the only two params that are send after the form, even though I've indicated :siren, :societe, :code_postal
{"user_id"=>"193",
"format"=>"84"}
I guess that this might also come from my Emmployeur controller:
class EmployeursController < ApplicationController
before_filter :set_user
def index
#employeurs = #user.employeur.all
end
def show
#employeur = Employeur.find(params[:id]) #This is where the error happens since no id is sent.
end
def new
#employeur = #user.build_employeur
end
def edit
#employeur = Employeur.find(params[:id])
end
def create
#employeur = #user.build_employeur(employeur_params)
respond_to do |format|
if #employeur.save
format.html { redirect_to [#user, #employeur], notice: 'Employeur was successfully created.' }
else
format.html { render action: 'new' }
format.json { render json: #employeur.errors, status: :unprocessable_entity }
end
end
end
def update
#employeur = Employeur.find(params[:id])
respond_to do |format|
if #employeur.update_attributes(employeur_params)
format.html { redirect_to [#user, #employeur], notice: 'Employeur was successfully created.' }
format.json { render action: 'show', status: :created, location: #employeur }
else
format.html { render action: 'new' }
format.json { render json: #employeur.errors, status: :unprocessable_entity }
end
end
end
def destroy
#employeur = Employeur.find(params[:id])
#employeur.destroy
respond_to do |format|
format.html { redirect_to #user }
format.json { head :no_content }
end
end
private
def set_user
#user = User.find(params[:user_id])
end
def employeur_params
params.require(:employeur).permit(:siren, :societe, :code_postal)
end
end
Any help would be more then welcome.
In order to give an example of singular and nested resource working, I'll add a little more of my code:
class Employeur < ActiveRecord::Base
model_name.instance_variable_set(:#route_key, 'employeur')
belongs_to :user
has_many :projets, as: :projetable
has_many :prestataires, through: :projets
has_many :offres, through: :projets
has_many :feedbacks, through: :projets
validates :siren, :societe, :code_postal, presence: true, uniqueness: true
validates :code_postal, presence: true
validates_associated :user
end
Here's mu User controller that leads me from the user form to the employeur once filled:
class UsersController < ApplicationController
#TODO index user doit être suprimé quand inutile pour dev
def index
#users = User.all
end
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
# GET /users/1/edit
def edit
#user = User.find(params[:id])
end
# POST /users
# POST /users.json
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
if params[:commit] == 'Employeur'
format.html { redirect_to new_user_employeur_path(user_id: #user), notice: "Renseignez vos informations d'employeur" }
format.json { render action: 'show', status: :created, location: #user }
else
format.html { redirect_to new_user_prestataire_path(user_id: #user), notice: "Renseignez vos informations de prestataire" }
format.json { render action: 'show', status: :created, location: #user }
end
else
format.html { render action: 'new' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update(user_params)
if params[:commit] == 'Prestataire'
format.html { redirect_to new_user_prestataire_path(user_id: #user), notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { redirect_to new_user_employeur_path(user_id: #user), notice: "User was successfully updated." }
format.json { head :no_content }
end
else
format.html { render action: 'edit' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
private
def user_params
params.require(:user).permit(:email, :password, :password_confirmation, :surname, :forename, :civility, :phone)
end
end
And finally, my User form:
<%= form_for(#user) do |f| %>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :civility, 'Titre de civilité: ' %><br>
<%= f.text_field :civility %>
</div>
<div class="field">
<%= f.label :forename, 'Prénom: ' %><br>
<%= f.text_field :forename %>
</div>
<div class="field">
<%= f.label :surname, 'Nom de famille: ' %><br>
<%= f.text_field :surname %>
</div>
<div class="field">
<%= f.label :email, 'Email: ' %><br>
<%= f.text_field :email %>
</div>
<div class="field">
<%= f.label :password, 'Mot de passe: ' %><br>
<%= f.password_field :password, size: 40 %>
</div>
<div class="field">
<%= f.label :password_confirmation, 'Confirmation de mot de passe: ' %><br>
<%= f.password_field :password_confirmation, size: 40 %>
</div>
<div class="field">
<%= f.label :phone, 'Numéro de téléphone: ' %><br>
<%= f.text_field :phone %>
</div>
<div class="actions">
<%= f.submit "Employeur" %>
<%= f.submit "Prestataire" %>
</div>
<% end %>
Hope this will help someone as much as it would have helped me. Cheers !
You are not passing in the #employeur to your nested route user_employeur_path. Try this on your form_for line:
user_employeur_path(#user, #employeur)
But you shouldn't have to specify url; this should work:
<%= form_for [#user,#employeur] do |f| %>
See creating paths and urls from objects.
You don't have your EmployeursController setup correctly. Since employeur is a singular resource, you cannot reference it by id. Instead you need to change your show action to this:
def show
#employeur = User.find(params[:user_id]).employeur
end
The reason is that user_employeur_path(#user) creates a path like /users/193/employeur where you can access the user id in the controller via params[:user_id]
Also, since employeur is a singular resource, there is no index action defined for it. You can remove the index action entirely from your controller.
For people like me who were desperate to find an example of nested and singular resource working, I post my controller corrected thanks to the help of Hamed:
class EmployeursController < ApplicationController
before_filter :set_user
def new
#employeur = #user.build_employeur
end
def show
#employeur = #user.employeur
end
def edit
#employeur = #user.employeur
end
def create
#employeur = #user.build_employeur(employeur_params)
respond_to do |format|
if #employeur.save
format.html { redirect_to [#user, #employeur], notice: 'Employeur was successfully created.' }
else
format.html { render action: 'new' }
format.json { render json: #employeur.errors, status: :unprocessable_entity }
end
end
end
def update
#employeur = #user.employeur
respond_to do |format|
if #employeur.update_attributes(employeur_params)
format.html { redirect_to [#user, #employeur], notice: 'Employeur was successfully created.' }
format.json { render action: 'show', status: :created, location: #employeur }
else
format.html { render action: 'new' }
format.json { render json: #employeur.errors, status: :unprocessable_entity }
end
end
end
def destroy
#employeur = #user.employeur
#employeur.destroy
respond_to do |format|
format.html { redirect_to root_path }
format.json { head :no_content }
end
end
private
def set_user
#user = User.find(params[:user_id])
end
def employeur_params
params.require(:employeur).permit(:siren, :societe, :code_postal)
end
end

Rails undefined method `model_name' for NilClass:Class, Agile web development, task G,

I am new to rails. When i read the task G , check out section, of Agile web development with rails. I get a very strange problem.
/home/chenhao/ruby/depot/app/views/orders/_form.html.erb where line #1 raised:
undefined method `model_name' for NilClass:Class
I guess the nil #order induce this error,but i have already initialized the #order in the new method of the controller. Could anyone help me slove this strange bug?
Here is the _form.html.erb
<%= form_for(#order) do |f| %>
<% if #order.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#order.errors.count, "error") %> prohibited this order from being saved:</h2>
<ul>
<% #order.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name, :size=>40 %>
</div>
<div class="field">
<%= f.label :address %><br />
<%= f.text_area :address, :row=>3, :col=>40 %>
</div>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, :size=>40 %>
</div>
<div class="field">
<%= f.label :pay_type %><br />
<%= f.select :pay_type, Order::PAYMENT_TYPES, :prompt=>"Select a payment method" %>
</div>
<div class="actions">
<%= f.submit "Place Order"%>
</div>
<% end %>
Here is the 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])
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
#cart = current_cart
if #cart.line_items.empty?
redirect_to store_url, :notice => 'Your cart is empty'
return
end
#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])
#order.add_line_items_from_cart(current_cart)
respond_to do |format|
if #order.save
Cart.destroy(session[:cart_id])
session[:cart_id] = nil
format.html { redirect_to store_url, notice: 'Thank you for your order.' }
format.json { render json: #order, status: :created, location: #order }
else
#cart = current_cart
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
And the model:
class Order < ActiveRecord::Base
has_many :line_items, :dependent => :destory
attr_accessible :address, :email, :name, :pay_type
PAYMENT_TYPES = ["Check", "Credit card","Purchase Order"]
validates :address, :email, :name, :presence => true
validates :pay_type, :inclusion => PAYMENT_TYPES
def add_line_items_from_cart(cart)
cart.line_items.each do |item|
item.cart_id = nil
line_items << item
end
end
end
i had same problem, i mistaken removed #order = Order.new from def new in orders_controller.rb
Try out with form_tag instead of form_for.
Or add resources :orders in your routes.rb file.

Cannot access model method inside its controller in Rails

In my Rails app, I have a controller tickets_controller.rb and model ticket.rb. For creating a ticket I have the following form,
<%= form_for(#ticket) do |f| %>
<% if #ticket.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#ticket.errors.count, "error") %> prohibited this ticket from being saved:</h2>
<ul>
<% #ticket.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.label :ref_no, "Reference Number"%><br/>
<%= f.text_field :ref_no%><br />
<%= f.label :category, "Type of Request"%><br/>
<%= f.text_field :category_id %><br />
<%= f.label :issue, "Issue"%><br/>
<%= f.text_area :issue%><br />
<%= f.label :ticket_priority, "Priority level"%><br/>
<%= f.text_field :ticket_priority_id %><br />
<%= f.label :ticket_status, "Current Status"%><br/>
<%= f.text_field :ticket_status_id %><br />
<%= f.label :project, "Project"%><br/>
<%= f.text_field :project_id %><br />
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I want to create a unique random reference number on the form_load (ticket/new), and it should be appended to Reference Number text field. While creating a new reference number, it should check the tickets table for duplication. So I have the following model,
ticket.rb
class Ticket < ActiveRecord::Base
attr_accessible :issue, :ticket_status_id, :ticket_priority_id, :ref_no, :category_id, :project_id
has_many :ticket_statuses , :through => :ticket_histories
has_one :ticket_priority
belongs_to :user
before_create :generate_token
protected
def generate_num
self.token = loop do
random_token = random(1000000000)
break random_token unless Ticket.exists?(:ref_no => random_token)
end
end
end
and
tickets_controller.rb
class TicketsController < ApplicationController
before_filter :authenticate_user!
#load_and_authorize_resource
def index
#tickets = Ticket.all
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #tickets }
end
end
def show
#ticket = Ticket.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render :json => #ticket }
end
end
def new
#ticket = Ticket.new
#ref_no = Ticket.generate_num
#categories = Category.all
#status = TicketStatus.first
#priorities = TicketPriority.all
respond_to do |format|
format.html # new.html.erb
format.json { render :json => #ticket }
end
end
def edit
#ticket = Ticket.find(params[:id])
end
def create
#ticket = Ticket.new(params[:ticket])
respond_to do |format|
if #ticket.save
format.html { redirect_to #ticket, :notice => 'Ticket was successfully created.' }
format.json { render :json => #ticket, :status => :created, :location => #ticket }
else
format.html { render :action => "new" }
format.json { render :json => #ticket.errors, :status => :unprocessable_entity }
end
end
end
def update
#ticket = Ticket.find(params[:id])
respond_to do |format|
if #ticket.update_attributes(params[:ticket])
format.html { redirect_to #ticket, :notice => 'Ticket was successfully updated.' }
format.json { head :no_content }
else
format.html { render :action => "edit" }
format.json { render :json => #ticket.errors, :status => :unprocessable_entity }
end
end
end
def destroy
#ticket = Ticket.find(params[:id])
#ticket.destroy
respond_to do |format|
format.html { redirect_to tickets_url }
format.json { head :no_content }
end
end
end
When I run my app, I am getting the following error. Can anyone help?
NoMethodError in TicketsController#new
undefined method `generate_num' for #<Class:0x7f5cdc1f21c0>
Rails.root: /home/local/Rajesh/ticket_system
Application Trace | Framework Trace | Full Trace
app/controllers/tickets_controller.rb:27:in `new'
Change your model method generate_num to self.generate_num.
def self.generate_num
token = loop do
random_token = random(1000000000)
break random_token unless Ticket.exists?(:ref_no => random_token)
end
end
You have defined and instance method and you are calling it using Class
Call method using object
#ticket.generate_num

Resources