Adding to has_one if text_field != blank or nil - ruby-on-rails

I have a simple has_one relationship setup but I want to add records to Damages table only when the text_field is not blank or nil. Right now it's adding records that are blank or nil to the other table.
My view:
<%= f.fields_for :damage do |builder| %>
<%= builder.label 'Damage' %><br />
<%= builder.text_field :dam_detail %>
<% end %>
Packjob Model:
class Packjob < ActiveRecord::Base
attr_accessible :pj_damage
has_one :damage
accepts_nested_attributes_for :damage
end
Damage Model:
class Damage < ActiveRecord::Base
attr_accessible :dam_detail
belongs_to :packjob
end
How do I allow only non blank or nil values being added?
Is best practice to add logic for this to the helper?
EDIT:
Here's the controller for Packjobs:
class PackjobsController < ApplicationController
# GET /packjobs
# GET /packjobs.json
def index
#packjobs = Packjob.includes(:damage).all
#packers = Packer.find(:all)
#rigs = Rig.find(:all, :order => "rig_type_number")
respond_to do |format|
format.html # index.html.erb
format.json { render json: #packjobs }
end
end
# GET /packjobs/1
# GET /packjobs/1.json
def show
#packjob = Packjob.find(params[:id])
#packers = Packer.find(:all)
respond_to do |format|
format.html # show.html.erb
format.json { render json: #packjob }
end
end
# GET /packjobs/new
# GET /packjobs/new.json
def new
#packjob = Packjob.new
#packers = Packer.find(:all, :conditions => { :p_team => "t" }, :order => "p_name")
#rigs = Rig.find(:all, :conditions => { :rig_status => "t" }, :order => "rig_type_number")
#damage = #packjob.build_damage
##book = #author.build_book
respond_to do |format|
format.html # new.html.erb
format.json { render json: #packjob }
end
end
# GET /packjobs/1/edit
def edit
#packjob = Packjob.find(params[:id])
#packers = Packer.find(:all, :conditions => { :p_team => "t" }, :order => "p_name")
#rigs = Rig.find(:all, :conditions => { :rig_status => "t" }, :order => "rig_type_number")
end
# POST /packjobs
# POST /packjobs.json
def create
#packjob = Packjob.new(params[:packjob])
#packers = Packer.find(:all, :conditions => { :p_team => "t" }, :order => "p_name")
#rigs = Rig.find(:all, :conditions => { :rig_status => "t" }, :order => "rig_type_number")
respond_to do |format|
if #packjob.save
format.html { redirect_to #packjob, notice: 'Packjob was successfully created.' }
format.json { render json: #packjob, status: :created, location: #packjob }
else
format.html { render action: "new" }
format.json { render json: #packjob.errors, status: :unprocessable_entity }
end
end
end
# PUT /packjobs/1
# PUT /packjobs/1.json
def update
#packjob = Packjob.find(params[:id])
#packers = Packer.find(:all, :conditions => { :p_team => "t" }, :order => "p_name")
#rigs = Rig.find(:all, :conditions => { :rig_status => "t" }, :order => "rig_type_number")
respond_to do |format|
if #packjob.update_attributes(params[:packjob])
format.html { redirect_to #packjob, notice: 'Packjob was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #packjob.errors, status: :unprocessable_entity }
end
end
end
# DELETE /packjobs/1
# DELETE /packjobs/1.json
def destroy
#packjob = Packjob.find(params[:id])
#packjob.destroy
respond_to do |format|
format.html { redirect_to packjobs_url }
format.json { head :no_content }
end
end
end
Also the I want the packjob to allow for blanks in damage text_field, I just don't want the records added to the Damages table..

This is a job for validations. Specifically, you want two things:
You want your Damage class to validate that :dam_detail is not blank or nil:
class Damage < ActiveRecord::Base
# ... rest of class here ...
validates :dam_detail, :presence => true, :length => { :minimum => 1 }
end
You want your Packjob class to validate that its contained Damage object is valid:
class Packjob < ActiveRecord::Base
# ... rest of class here ...
validates_associated :damage
end
I also recommend modifying your database schema to add the restriction that the dam_detail field cannot be null. See the migrations guide for more info.

Even though its more commonly used for has_many the cocoon gem https://github.com/nathanvda/cocoon is great for this. That gem will allow you to build the relation on the fly from the front end. it will also allow you to destroy the relation too.

Related

How to parse nested JSON object in Rails?

I'm sending the following JSON to Rails 4.1.0
Started POST "/orders.json" for 127.0.0.1 at 2015-08-11 15:19:34 +0200
Processing by OrdersController#create as JSON
Parameters: {"order"=>{"name"=>"Jon", "surname"=>"Do", "line_items_attributes"=>[{"work_id"=>16, "quantity"=>1, "total_price"=>34.5}, {"work_id"=>12, "quantity"=>2, "total_price"=>40}]}}
Unpermitted parameters: line_items_attributes
but I'm getting Unpermitted parameters error. My Order model:
class Order < ActiveRecord::Base
belongs_to :user
belongs_to :dispatch_method
belongs_to :payment_method
has_many :line_items, :dependent => :destroy
accepts_nested_attributes_for :line_items
end
My orders_controller.rb
class OrdersController < ApplicationController
before_action :set_order, only: [:show, :edit, :update, :destroy]
def index
#orders = Order.all
end
def show
end
def new
#order = Order.new
end
def edit
end
def create
#order = Order.create(order_params)
respond_to do |format|
if #order.save
format.html { redirect_to #order, notice: 'Order was successfully created.' }
format.json { render action: 'show', status: :created, location: #order }
else
format.html { render action: 'new' }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #order.update(order_params)
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
def destroy
#order.destroy
respond_to do |format|
format.html { redirect_to orders_url }
format.json { head :no_content }
end
end
private
def set_order
#order = Order.find(params[:id])
end
def order_params
params.require(:order).permit(:name, :surname, line_items_attributes: [:id, :work_id, :quantity, :total_price])
end
end
I'm able to create and save a new instance of order, but not of a line_item.
You can try to redefine your order_params like this:
def order_params
json_params = ActionController::Parameters.new(JSON.parse(params[:order]))
return json_params.require(:name, :surname).permit(line_items_attributes: [:id, :work_id, :quantity, :total_price])
end
As you see, I am parsing params[:order] to avoid parsing the full params var. You might need to add another json level here but I hope you get the idea.
something like this
render :json => #booking, :include => [:paypal,
:boat_people,
:boat => {:only => :name, :include => {:port => {:only => :name, :include => {:city => {:only => :name, :include => {:country => {:only => :name}}}}},
:boat_model => {:only => :name, :include => {:boat_type => {:only => :name}}}}}]

Ruby on Rails: many-to-many association undefined methode on creation

I have set up members and teams models using has_many through association.
member.rb
has_many :teams, :through => :team_members
has_many :team_members
team.rb
has_many :members, :through => :team_members
has_many :team_members
team_member.rb
belongs_to :member
belongs_to :team
When I try to create a new team, I get this error:
undefined method `name' for nil:NilClass
params are:
{"utf8"=>"✓",
"authenticity_token"=>"aXpMxWxGlhogfn9EbBWciSjoMrYXbPxG8Kzha14na58=",
"team"=>{"name"=>"Ruby",
"email"=>"email#email.com",
"language"=>"En",
"link"=>"",
"logo"=>#<ActionDispatch::Http::UploadedFile:0xb3907f0 #original_filename="You-Are-Great-.gif",
#content_type="image/gif",
#headers="Content-Disposition: form-data; name=\"team[logo]\"; filename=\"You-Are-Great-.gif\"\r\nContent-Type: image/gif\r\n",
#tempfile=#<File:/tmp/RackMultipart20120723-1907-m3bi79>>},
"commit"=>"Create Team"}
The create method in teams_controller.rb is:
#team = Team.new(params[:team])
The team doesn't get created unless I assign the attributes manually one by one like
#team = Team.new(:name => params[:team][:name], :email => params[:team][:email]...)
and so! any ideas why?
EDIT:
teams_controller.rb:
class TeamsController < ApplicationController
# GET /teams
# GET /teams.json
def index
#teams = Team.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #teams }
end
end
# GET /teams/1
# GET /teams/1.json
def show
#team = Team.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #team }
end
end
# GET /teams/new
# GET /teams/new.json
def new
#team = Team.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #team }
end
end
# GET /teams/1/edit
def edit
#team = Team.find(params[:id])
end
# POST /teams
# POST /teams.json
def create
raise params.to_yaml
#team = Team.new(params[:team])
respond_to do |format|
if #team.save
#team_member = TeamMember.new(:team_id => #team.id, :member_id => current_member.id,
:accepted => true, :leader => true, :joined => Time.now)
if #team_member.save
format.html { redirect_to team_path(#team), notice: 'Team was successfully created.' }
format.json { render json: #team, status: :created, location: #team }
else
#team.destroy
format.html { render action: "new" }
format.json { render json: #team.errors, status: :unprocessable_entity }
end
else
format.html { render action: "new" }
format.json { render json: #team.errors, status: :unprocessable_entity }
end
end
end
# PUT /teams/1
# PUT /teams/1.json
def update
#team = Team.find(params[:id])
respond_to do |format|
if #team.update_attributes(params[:team])
format.html { redirect_to #team, notice: 'Team was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #team.errors, status: :unprocessable_entity }
end
end
end
# DELETE /teams/1
# DELETE /teams/1.json
def destroy
#team = Team.find(params[:id])
#team.destroy
respond_to do |format|
format.html { redirect_to teams_url }
format.json { head :no_content }
end
end
end
team.rb model:
class Team < ActiveRecord::Base
attr_accessible :name, :email, :language, :link, :logo, :team_leader
validates_presence_of :name
validates_presence_of :email
validates_presence_of :language
validates_uniqueness_of :name
has_many :leaders, :class_name => "TeamMember", :conditions => { :leader => true }
has_many :members, :through => :team_members
has_many :team_members, :conditions => { :accepted => true, :active => true }
has_attached_file :logo,
:styles => { :medium => "320x180>", :thumb => "100x100>" },
:url => "/assets/teams/:id/:style/:basename.:extension",
:path => ":rails_root/public/assets/teams/:id/:style/:basename.:extension"
end

rails 3 get data from an association and display in flash message

I'm using ActiveMerchant with Authorize.net and already setup 2 models Order and Transaction. (http://railscasts.com/episodes/145-integrating-active-merchant)
I would like to get error message from the transaction if error occurred then output in flash message. Here is my code:
#order_controller.rb
def create
#order = Order.new(params[:order])
respond_to do |format|
if #order.save
if #order.purchase
format.html { redirect_to(#order, :notice => 'Order was successfully created.') }
format.xml { render :xml => #order, :status => :created, :location => #order }
else
flash[:error] = #order.transactions.response
format.html { render :action => "new" }
end
else
format.html { render :action => "new" }
format.xml { render :xml => #order.errors, :status => :unprocessable_entity }
end
end
end
And here is my transaction model:
#models/order_transaction.rb
class OrderTransaction < ActiveRecord::Base
belongs_to :order
serialize :params
def response=(response)
self.success = response.success?
self.authorization = response.authorization
self.message = response.message
self.params = response.params
rescue ActiveMerchant::ActiveMerchantError => e
self.success = false
self.authorization = nil
self.message = e.message
self.params = {}
end
end
The transaction data has been saved to the database as below:
#models/order.rb
class Order < ActiveRecord::Base
has_many :transactions, :class_name => "OrderTransaction"
attr_accessor :card_type, :card_number, :card_month, :card_year, :card_verification
def purchase
response = GATEWAY.purchase(charge_amount, credit_card, purchase_options)
transactions.create!(:action => "purchase", :amount => charge_amount, :response => response)
response.success?
end
...
end
I want to flash up this transaction error message when transaction failed. And what would I should do to get these errors if I have 2 transactions for one order.?
Any help would be much appreciated.
Thanks!

Nested attributes in ROR

I'm trying to create an application where users can freely create shops and associated shop item for a specific shop is displayed when a show action is called but I seem to be doing something wrong. Any help here will be appreciated. I have attached shots of my code below.
class ShopItem < ActiveRecord::Base
belongs_to :shop
def self.find_shop_items_for_sale
find(:all, :order => "title", :conditions => ["shop_id = ?", #shop.id])
end
end
class Shop < ActiveRecord::Base
has_many :shop_items
end
#Controllers
class ShopsController < ApplicationController
def new
#shop = Shop.new
end
def create
#shop = Shop.new(params[:shop])
#shop.user_id = current_user.id
respond_to do |format|
if #shop.save
flash[:notice] = "Successfully created shop."
format.html {redirect_to(all_shops_shops_url)}
format.xml {render :xml => #shop, :status => :created, :location => #shop }
else
format.html {render :action => 'new'}
format.xml { render :xml => #shop.errors, :status => :unprocessable_entity }
end
end
end
def show
#shop = Shop.find(params[:id])
#shop_items = ShopItem.find_shop_items_for_sale
#shop_cart = find_shop_cart
end
class ShopItemsController < ApplicationController
def user
#per_page ||= 5
#user = User.find(params[:id])
#shop_items = ShopItem.find(:all, :conditions=>["user_id = ?", #user.id], :order=>"id desc")
end
def show
#shop_item = ShopItem.find(params[:id])
#shop = #shop_item.shop
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #shop_item }
end
end
# GET /shop_items/new
# GET /shop_items/new.xml
def new
#shop_item = ShopItem.new
#shop = Shop.find(params[:id])
##shop_items = ShopItem.paginate(:all, :condition=>["shop_id] = ?", #shop.id], :order=> "id desc", :page => params[:page],:per_page => #per_page)
#shop_items = ShopItem.find(:all, :conditions=>["shop_id = ?", #shop.id], :order=> "id desc")
#shop_item.shop_id = params[:id]
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #shop_item }
end
end
# GET /shop_items/1/edit
def edit
#shop_item = ShopItem.find(params[:id])
end
# POST /shop_items
# POST /shop_items.xml
def create
#shop_item = ShopItem.new(params[:shop_item])
#shop_item.user_id = current_user.id
respond_to do |format|
if #shop_item.save
flash[:notice] = 'Shop item was successfully created.'
format.html { redirect_to(#shop_item) }
format.xml { render :xml => #shop_item, :status => :created, :location => #shop_item }
else
#shop = Shop.find(#shop_item.shop_id)
##shop_items = ShopItem.paginate(:all, :condition =>["shop_id = ?", #shop.id], :order=> "id desc" , :page => params[:page], :per_page => #per_page)
#shop_items = ShopItem.find(:all, :conditions =>["shop_id = ?", #shop.id], :order=> "id desc")
format.html { render :action => "new" }
format.xml { render :xml => #shop_item.errors, :status => :unprocessable_entity }
end
end
end
If you specify that shop :has_many :shop_items, then you don't have to specify actions like find_shop_items_for_sale. Just call:
#shop = Shop.find(params[:id])
#shop_items = #shop.shop_items
Also trying to retrive all shop items for user (action user) is a bad idea. Instead take a look on will_paginate gem.
On the other side, your question isn't question at all and it would be much easier if you will ask a specific question, or just try to explain what problems you have.

Nil foreign key in a nested form

I have a nested form with the following models:
class Incident < ActiveRecord::Base
has_many :incident_notes
belongs_to :customer
belongs_to :user
has_one :incident_status
accepts_nested_attributes_for :incident_notes, :allow_destroy => false
end
class IncidentNote < ActiveRecord::Base
belongs_to :incident
belongs_to :user
end
Here is the controller for creating a new Incident.
def new
#incident = Incident.new
#users = #customer.users
#statuses = IncidentStatus.find(:all)
#incident.incident_notes.build(:user_id => current_user.id)
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #incident }
end
end
def create
#incident = #customer.incidents.build(params[:incident])
#incident.incident_notes.build(:user_id => current_user.id)
respond_to do |format|
if #incident.save
flash[:notice] = 'Incident was successfully created.'
format.html { redirect_to(#incident) }
format.xml { render :xml => #incident, :status => :created, :location => #incident }
else
format.html { render :action => "new" }
format.xml { render :xml => #incident.errors, :status => :unprocessable_entity }
end
end
end
This all exists in a nested form for an incident. There is a text area for the incident_notes form that is nested in the incident.
So my problem is that the incident_notes entry is submitted twice whenever I create the incident. The first insert statement creates an incident_note entry with the text from the text area, but it doesn't attach the user_id of the user as the foreign key. The second entry does not contain the text, but it has the user_id.
I thought I could do this with:
#incident.incident_notes.build(:user_id => current_user.id)
but that does not appear to work the way I want. How can I attach the user_id to incident_note?
Thanks!
I finally figured it out. I needed to do this in the Incident controller:
def create
#incident = #customer.incidents.build(params[:incident])
#incident.incident_notes.first.user = current_user
rather than:
def create
#incident = #customer.incidents.build(params[:incident])
#incident.incident_notes.build(:user_id => current_user.id)
I don't think you need
#incident.incident_notes.build(:user_id => current_user.id)
on new action. You're building the incident_notes twice.

Resources