Nested form, update and creation in one form - ruby-on-rails-4

I wanted to set up a form where I can edit some nested objects and create new objects at the same time.
Thats what I got until now:
Models:
class Rate < ActiveRecord::Base
belongs_to :org_unit
validates_uniqueness_of :name
validates_presence_of :name, :tablename, :rate_order_no, :ratevalue
end
class OrgUnit < ActiveRecord::Base
has_many :rates
accepts_nested_attributes_for :rates
end
Controller:
class OrgUnitsController < ApplicationController
before_action :set_org_unit, only: [:show, :edit]
def index
#org_units = OrgUnit.all
end
def show
end
def edit
end
def update
if #org_unit.update(org_unit_params)
redirect_to #org_unit, notice: 'Update successfull.'
else
render action: 'edit'
end
end
private
def set_org_unit
#org_unit = OrgUnit.find(params[:id])
#rates = #org_unit.rates
end
def org_unit_params
params.require(:org_unit).permit(
:rates_attributes => [:name, :tablename, :rate_order_no, :ratevalue]
)
end
end
Routes:
#Organisation Units
get '/org_units/', :to => 'org_units#index', :as => 'org_units'
get '/org_units/:id', :to => 'org_units#show', :as => 'org_unit'
get '/org_units/:id/edit', :to => 'org_units#edit', :as => 'edit_org_unit'
put '/org_units/:id', :to => 'org_units#update'
patch '/org_units/:id', :to => 'org_units#update'
View:
<%= simple_nested_form_for #org_unit do |f| %>
<table id="ratetable" class="display">
<thead>
<tr> <th>Rate Name</th> <th>Table</th> <th>Department</th> <th>Value</th> </tr>
</thead>
<tbody>
<%= f.simple_fields_for :rates, :wrapper => false do |ff| %>
<tr class="fields">
<td><%= ff.input :name, label: false, required: true %></td>
<td><%= ff.input :tablename, collection: ["Costs","Savings","CnQ"], label:false, required: true, prompt: "Select the table" %></td>
<td><%= ff.input :rate_order_no, collection: 1..19, label:false, required: true, prompt: "Select the row"%></td>
<td><%= ff.input :ratevalue, label: false, required: true %></td>
</tr>
<% end %>
</tbody>
</table>
<p><%= f.link_to_add "Add a rate", :rates, :data => { :target => "#ratetable" }, :class => "btn btn-default" %></p>
<br>
<br>
<%= f.submit "Save Rates", :class => "btn bnt-default" %>
<% end %>
Now if I click the submit button rails is taking every filled line and create a new rate with the attributes of org_unit_params. So the old rates are not updated and multiple times in my database then.
What I want is that he updates the old ones if they changed and create new records for the others.
It should have something to do with create_or_update but I cant put it together.
Would appreciate every hint.
Thanks in advance and best regards.

Okay I had to add :id to my permitted attributes:
def org_unit_params
params.require(:org_unit).permit(:id, :name,
rates_attributes: [:id, :name, :tablename, :rate_order_no, :ratevalue, :org_unit_id, :_destroy]
)
end
But that wasnt enough :( So I had to add a hidden input field with :id in my fields_for and now it works:
<%= f.simple_fields_for :rates, :wrapper => false do |ff| %>
<tr class="fields">
<td><%= ff.input :name, label: false %></td>
<td><%= ff.input :tablename, collection: ["Costs","Savings","CnQ"], label:false, prompt: "Select the table" %></td>
<td><%= ff.input :rate_order_no, collection: 1..19, label:false, prompt: "Select the row"%></td>
<td><%= ff.input :ratevalue, label: false, required: true %></td>
<td><%= ff.link_to_remove "Remove", :class => "btn btn-default" %></td>
<%= ff.input :id, :as => :hidden %>
</tr>
<% end %>

Related

How to view and edit the uploaded excel sheets in rails using carrierwave gem (win7)

I am new to rails and wants to do following tasks with my uploader-
1) view the uploaded excel sheets in rails in editable mode
2)save that edited sheet in database(sqlite3).
I am seriously not getting what to do with this "view method"(in controller) to get my solution that's why leaving view method empty.
Also, please explain what is "resume.attachment_url" doing in
<%= link_to "Download Resume", resume.attachment_url %> in index.html.erb .
Thanks,
Aarzoo Goyal
routes.rb
Rails.application.routes.draw do
resources :resumes, only: [:index, :new, :create, :destroy]
root "resumes#index"
get 'resumes/index'
get 'resumes/new'
get 'resumes/create'
get 'resumes/destroy'
Model-Resume.rb
class Resume < ActiveRecord::Base
mount_uploader :attachment, AttachmentUploader # Tells rails to use this uploader for this model.
validates :name, presence: true # Make sure the owner's name is present.
validates :attachment, presence: true
end
resume_controller.rb
class ResumesController < ApplicationController
def index
#resumes = Resume.all
end
def new
#resume = Resume.new
end
def create
#resume = Resume.new(resume_params)
if #resume.save
redirect_to resumes_path, notice: "The resume #{#resume.name} has been uploaded."
else
render "new"
end
end
def view
end
def destroy
#resume = Resume.find(params[:id])
#resume.destroy
redirect_to resumes_path, notice: "The resume #{#resume.name} has been deleted."
end
private
def resume_params
params.require(:resume).permit(:name, :attachment)
end
end
new.html.erb
<% if !#resume.errors.empty? %>
<div class = "alert alert-error">
<ul>
<% #resume.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class = "well">
<%= form_for #resume, html: { multipart: true } do |f| %>
<%= f.label :name %>
<%= f.text_field :name %><br />
<%= f.label :attachment %>
<%= f.file_field :attachment %><br />
<%= f.submit "Save", class: "btn btn-primary" %>
<% end %>
</div>
index.html.erb
<% if !flash[:notice].blank?%>
<div class="alert alert-info">
<%= flash[:notice]%>
</div>
<%end%>
<br />
<%= link_to "New File", new_resume_path, class: "btn btn-primary"%>
<br />
<br />
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Name</th>
<th>Download Link</th>
<th>View</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
<% #resumes.each do|resume| %>
<tr>
<td><%= resume.name%></td>
<td><%= link_to "Download Resume", resume.attachment_url %></td>
<td><%= link_to "View "%></td>
<td><%= button_to "Delete", resume, method: :delete, class: "btn btn-danger", confirm: "Are you sure to delete #{resume.name}?" %></td>
</tr>
<% end %>
</tbody>
</table>

couldn't find Object with id=

I'm trying to add a column to a table that displays all the products in my active record that will allow me to remove a product for a given row. When I try to run the code I get an error that matched the title.
Products Controller
def destroy
#product = Product.find(params[:id])
#product.destroy
redirect_to :back
end
private
def product_params
params.require(:product).permit(:ta_code, :tatr, :oem, :name, :kind, :ta_type, :id)
end
Delete Button section of code
<% Product.all.each do |product| %>
<% if product.kind == "oem" %>
<tr data-toggle="collapse" data-target="#all<%= product.tatr %>" class="accordion-toggle">
<% if can? :destroy, Product %>
<td><%= button_to "delete", delete_path(#product), :method => :delete %></td>
<% end %>
<td><%= product.id %></td>
<td><%= product.tatr %></td>
<td><%= product.name %></td>
<td><%= product.oem %></td>
<td><%= product.created_at.strftime("%b/%d/%y") %></td>
</tr>
<% end %>
Routes.rb
get 'signup' => 'users#new'
root 'static#home'
get 'systems' => 'static#pages'
get 'help' => 'static#help'
get 'ce' => 'static#ce'
get 'oem' => 'static#oem'
get 'update_existing' => 'static#update_existing'
get 'reports' => 'static#reports'
get 'miscellaneous' => 'static#miscellaneous'
get 'login' => 'sessions#new'
post 'login' => 'sessions#create'
delete 'logout' => 'sessions#destroy'
get 'create_new' => 'products#new'
delete 'delete'=> 'products#destroy'
get 'new_status' => 'microposts#new'
get 'list' => 'users#list'
resources :users
resources :products
resources :microposts
This is my first real project so I'm sure the convention is a little off and organization may be lacking, but that comes with time. I appreciate any help.
You're passing an object instead of it's id here:
<% if can? :destroy, Product %>
<td><%= button_to "delete", delete_path(:id => product), :method => :delete %></td>
<% end %>
It should be delete_path(product) or delete_path(id: product.id)
Replace
delete_path(#product)
with
delete_path(product)

Ransack Undefined Method _path Rails 4.2.1

I'm working on a very simple CRUD Asset Management app and I want to use Ransack. I think I have this setup properly in my view and controller but each time the index view is hit I get the exception:
undefined methodassets_path' for #<#:0x007fa5f353e9e0>`
Here is my view:
index.html.erb
<div class="pull-right">
<%= search_form_for #q do |f| %>
<%= f.search_field :asset_name_cont, placeholder: 'Search...' %>
<% end %>
<table class="table table-striped">
<thead>
<tr>
<th>Asset Number</th>
<th>Asset Name</th>
<th>Serial Number</th>
<th>Model</th>
<th>Manufacturer</th>
<th>Asset Type</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% #assets.each do |a| %>
<tr>
<td><%= a.asset_number %></td>
<td><%= a.asset_name %></td>
<td><%= a.asset_serial %></td>
<td><%= a.asset_model %></td>
<td><%= a.asset_manuf %></td>
<td><%= a.asset_type.try(:name) %></td>
<td><%= link_to 'View', inventory_path(a), :class => 'btn btn-mini btn-info' %> <%= link_to 'Edit', edit_inventory_path(a), :class => 'btn btn-mini btn-warning' %></td>
</tr>
</tbody>
<% end %>
<%= will_paginate #assets %>
Here is my controller excerpt:
inventory_controller.rb
def index
#q = Asset.ransack(params[:q])
#assets = #q.result.order("asset_number ASC").paginate(:page => params[:page], :per_page => 10)
end
And here is my model (with annotation of the fields)
asset.rb
id :integer not null, primary key
asset_number :string
asset_shortname :string
asset_name :string
asset_desc :text
asset_serial :string
asset_model :string
asset_manuf :string
asset_type_id :integer
created_at :datetime not null
updated_at :datetime not null
asset_location :string
class Asset < ActiveRecord::Base
extend FriendlyId
friendly_id :asset_name, use: :slugged
validates :asset_name, :asset_serial, :asset_type_id, :asset_model, :asset_manuf, :presence => true
belongs_to :asset_type
end
I think I have the controller wired up fine, I was having issues before with forms and routes by having a controller called assets which is an issue as a reserved name in Rails 4.x.x so I rebuilt the controller as inventory and call the Asset class from within.
My question is, I the search_form_for field to look at the Asset model's field for asset_name but when I write the view as I've laid out I constantly get that path error.
Is there a way to pass a different path into the Ransack search_field method so that I can get past what seems to be an issue with conventions?
If you need more information or if my question is not clear enough, please do not hesitate to edit or ask for more information. Thanks all!
Ok, I figured this out. Similar to issues I was seeing with breaking Rails naming conventions in my other forms, I had to pass the url and method in the search_form_for helper method. It's working!
Here's my view for the search now:
<%= search_form_for(#q, url: "/inventory", method: :get) do |f| %>
<%= f.search_field :asset_name_cont, placeholder: 'Search...' %>
<% end %>

Why doesn't article.tag_list display the tags?

I have added gem 'acts-as-taggable-on' -v 2.3.1 in Gemfile.
Rails version 3.2.13, Ruby -v 1.9.3
In article.rb,
class Article < ActiveRecord::Base
acts_as_taggable_on :tags
has_many :comments, dependent: :destroy
validates :title, presence: true,
length: { minimum: 5 }
end
In articles_controller.rb,
class ArticlesController < ApplicationController
before_filter :authenticate_author!, except: [:index, :show]
def index
myarray = Article.all
#articles = Kaminari.paginate_array(myarray).page(params[:page]).per(10)
end
def show
#article = Article.find(params[:id])
end
def new
#article = Article.new
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to #article
else
render 'new'
end
end
def edit
#article = Article.find(params[:id])
end
def update
#article = Article.find(params[:id])
if #article.update_attributes(article_params)
redirect_to #article
else
render 'edit'
end
end
def destroy
#article = Article.find(params[:id])
#article.destroy
redirect_to articles_path
end
private
def article_params
params.require(:article).permit(:title, :text, :tag_list => [])
end
end
In articles/_form.html.erb
<div class="field">
<%= f.label :tag_list, "Tags (separated by commas)" %><br />
<%= f.text_field :tag_list %>
</div>
I ran the following commands after installing the acts-on-taggable-gem,
rails generate acts_as_taggable_on:migration
rake db:migrate
In articles/index.html.erb
<% #articles.each do |article| %>
<tr>
<td><%= article.title %></td>
<td><%= article.text %></td>
<td><%= article.tag_list %></td>
<td><%= link_to 'Show', article_path(article) %></td>
<% if author_signed_in? %>
<td><%= link_to 'Edit', edit_article_path(article) %></td>
<td><%= link_to 'Destroy', article_path(article),
method: :delete,
data: { confirm: 'Are you sure?' } %></td>
<% end%>
</tr>
<% end %>
The tags are not being displayed in the index page.
But if I do ,
article = Article.new(:title => "Awesome")
article.tag_list = "awesome, cool"
article.save
The transaction gets committed and the tags are displayed on the browser.
Why aren't the tags getting saved and displayed in the index page?
The Tag List is an array, which means you need to 'loop' to extract the data. Whenever I have used acts_as_taggable I run through a loop to extract the tags. Something like the following should work:
<% #articles.each do |article| %>
<tr>
<td><%= article.title %></td>
<td><%= article.text %></td>
<td>
<% article.tag_list.each do |tag| %>
<%= tag %>
<% end %>
</td>
<td><%= link_to 'Show', article_path(article) %></td>
<% if author_signed_in? %>
<td><%= link_to 'Edit', edit_article_path(article) %></td>
<td><%= link_to 'Destroy', article_path(article),
method: :delete,
data: { confirm: 'Are you sure?' } %></td>
<% end%>
</tr>
<% end %>

Returning view to page I started from when deleting a user in a Rails view

Environment:
OS: Windows 8.1
Ruby: 2.1.5
Rails: 4.2
In my views/users/index.html.erb, I have:
<h1>Listing Users</h1>
<span class="eastdev_pagination">
<%= will_paginate #users, :container => false %>
</span>
<table class="table table-striped">
<thead>
<tr>
<th>First</th>
<th>Last</th>
<th>Work phone</th>
<th>City</th>
<th>Organization</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #users.each do |u| %>
<tr>
<td><%= u.first %></td>
<td><%= u.last %></td>
<% if u.work_phone %>
<% phone = number_to_phone(u.work_phone, area_code: true) %>
<td><%= phone %></td>
<% else %>
<td></td>
<% end %>
<td><%= u.city %></td>
<td><%= u.organization %></td>
<%= render partial: "layouts/show_edit_del_buttons", locals: {my_model: u} %>
</tr>
<% end %>
</tbody>
</table>
<span class="eastdev_pagination">
<%= will_paginate #users, :container => false %>
</span>
<br>
In my layouts/show_edit_del_buttons.html.erb, I have:
<td>
<%= link_to my_model, class: 'btn btn-info', title: 'View', 'data-toggle' => 'tooltip', 'data-placement' => 'right' do %>
<span class="glyphicon glyphicon-search"></span>
<% end %>
<td>
<% if staff_access_level? %>
<td>
<%= link_to [:edit, my_model], class: 'btn btn-warning', title: 'Edit', 'data-toggle' => 'tooltip', 'data-placement' => 'right' do %>
<span class="glyphicon glyphicon-pencil"></span>
<% end %>
</td>
<td>
<%= link_to my_model, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', title: 'Delete', 'data-toggle' => 'tooltip', 'data-placement' => 'right' do %>
<span class="glyphicon glyphicon-remove"></span>
<% end %>
</td>
<% end %>
In my controllers/users.rb, I have the following:
def index
if params && params.has_key?('search-form')
item = params['search-form']
#users = User.where("first = ? OR last = ? OR organization LIKE ? AND approved = 1", item, item, "%#{item}%").paginate(:page => params[:page], per_page: 5).order('last')
else
#users = User.where("approved = 1").paginate(page: params[:page], per_page: 5)
end
end
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
The issue I am having, is that when I delete a user, I am returned to the first page. For example, I am on page 5 of the pagination, and I delete a user here, I am returned to the first navigation page.
How do I get the view to go back to the page I was on prior to the deletion?
Notes:
If I try something like:
<%= link_to my_model(:page => params[:page]), method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', title: 'Delete', 'data-toggle' => 'tooltip', 'data-placement' => 'right' do %>
<span class="glyphicon glyphicon-remove"></span>
<% end %>>
I get an error message:
Method not found: my_model
You should redirect user after delete on page you were on.
Look at your destroy method
redirect_to users_url
Here you should define a page while redirect.
Like this
my_model = Your path, like user_path(user, page: params[:page])
<%= link_to user_path(user, page: params[:page]), method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', title: 'Delete', 'data-toggle' => 'tooltip', 'data-placement' => 'right' do %>
<span class="glyphicon glyphicon-remove"></span>
<% end %>
You will get current page number in side destroy method
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to params[:page] ? users_url(page: params[:page]) : users_url }
format.json { head :no_content }
end
end