Hi i know it's silly but true i got this when i edit any entry.
I have an expense model and an expense_line_item and a paid_line_item model, it is created properly when i create a new entry but on editing previous entry it adds a new entry instead of updating, i. e. at update action it fires insert query. here is my code:
My controller:
def new
#menu = 'Expenses'
#page_name = 'Record New Expenses'
#expense = Expense.new
#expense.expense_line_items.build
#expense.paid_line_items.build
#expense.voucher_number = "EXP"+Time.now.to_i.to_s
#from_accounts = TransactionType.fetch_from_accounts(current_company.id, 'payments')
#to_accounts = TransactionType.fetch_to_accounts(current_company.id, 'payments')
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #expense }
end
end
# GET /expenses/1/edit
def edit
#menu = 'Expenses'
#page_name = 'Edit Expenses Entry'
#expense = Expense.find(params[:id])
#from_accounts = TransactionType.fetch_from_accounts(current_company.id, 'payments')
#to_accounts = TransactionType.fetch_to_accounts(current_company.id, 'payments')
end
# POST /expenses
# POST /expenses.xml
def create
#expense = Expense.new(params[:expense])
#expense.created_by = current_user.id
#expense.company_id = current_company.id
respond_to do |format|
if #expense.save
format.html { redirect_to(#expense, :notice => 'Expense was successfully created.') }
format.xml { render :xml => #expense, :status => :created, :location => #expense }
else
#menu = 'Expenses'
#page_name = 'Record New Expenses'
#from_accounts = TransactionType.fetch_from_accounts(current_company.id, 'payments')
#to_accounts = TransactionType.fetch_to_accounts(current_company.id, 'payments')
format.html { render :action => "new" }
format.xml { render :xml => #expense.errors, :status => :unprocessable_entity }
end
end
end
# PUT /expenses/1
# PUT /expenses/1.xml
def update
#expense = Expense.find(params[:id])
respond_to do |format|
if #expense.update_attributes(params[:expense])
format.html { redirect_to(#expense, :notice => 'Expense was successfully updated.') }
format.xml { head :ok }
else
#menu = 'Expenses'
#page_name = 'Edit Expenses Entry'
format.html { render :action => "edit" }
format.xml { render :xml => #expense.errors, :status => :unprocessable_entity }
end
end
end
My Model:
expense model:
class Expense < ActiveRecord::Base
has_many :expense_line_items
has_many :paid_line_items
accepts_nested_attributes_for :expense_line_items, :reject_if => lambda {|a| a[:account_id].blank? } , :allow_destroy => true
accepts_nested_attributes_for :paid_line_items, :reject_if => lambda {|a| a[:account_id].blank? }, :allow_destroy => true
#validations
validates_presence_of :expense_date, :voucher_number
validates_presence_of :expense_line_items
validates_associated :expense_line_items
validates_presence_of :paid_line_items
validates_associated :paid_line_items
end
expense_line_item:
class ExpenseLineItem < ActiveRecord::Base
belongs_to :expense
end
paid_line_item:
class PaidLineItem < ActiveRecord::Base
belongs_to :expense
end
My form :
<%= form_for(#expense) do |f| %>
<% #expense.expense_line_items.each_with_index do |expense_line_item, index| %>
<%= render "expense_line_items", :expense_line_item => expense_line_item, :index => index %>
<% end %>
<tr id="row_link" valign="top">
<td valign="top" colspan="6">
<%= link_to "Add new row",{:action => :add_row, :index => #expense.expense_line_items.size}, :remote => true %>
</td>
</tr>
<% #expense.paid_line_items.each_with_index do |paid_line_item, index| %>
<%= render "paid_line_items", :paid_line_item => paid_line_item, :index => index %>
<% end %>
<tr id="to_row_link" valign="top">
<td valign="top" colspan="6">
<%= link_to "Add new row",{:action => :add_to_row, :index => #expense.paid_line_items.size}, :remote => true %>
</td>
</tr>
<% end %>
i got frustrated, thanks in advance .
i have found a solution for this problem. When i tried to update a lineitem it take it as a new one hence i have to pass a hidden lineitem_id for update action. i have used
below code :
<%= hidden_field_tag "expense[expense_line_items_attributes][#{index}][id]",expense_line_item.id%>
and it works for me.
Related
I know there are a couple questions around this topic, one is almost identical since we followed the same tutorial, but none of the answers are working for me. I followed emerson lackey's tutorial on attaching multiple images with paperclip (http://emersonlackey.com/screencasts/rails-3-with-paperclip.mov) and am having the error Can't mass-assign protected attributes: assets_attributes. One note as you look at the code, I had been running with only image per post so there is terminology for images vs. assets that will be deleted but need right now for the rest of the site to work.
I have created an Asset ID and added it to the asset model. Also note that I have Pins instead of Posts.
In the pin.rb Model:
class Pin < ActiveRecord::Base
attr_accessible :description, :image, :image_remote_url, :Designer, :price, :retail_value, :condition, :lender_notes, :size, :material, :color, :classification, :item_category, :asset_attributes
validates :user_id, presence: true
validates :description, presence: true
validates :Designer, presence: true
validates :size, presence: true
validates :color, presence: true
validates :material, presence: true
validates :price, presence: true
validates :retail_value, presence: true
validates :condition, presence: true
validates :lender_notes, presence: true
validates :classification, presence: true
validates :item_category, presence: true
validates_attachment :asset, presence: true,
content_type: { content_type: ['image/jpeg', 'image/jpg', 'image/png', 'image/gif'] },
size: { less_than: 5.megabytes }
belongs_to :user
has_many :line_items
has_many :assets
accepts_nested_attributes_for :assets, :allow_destroy => true
before_destroy :ensure_not_referenced_by_any_line_item
has_attached_file :image, styles: { medium: "320x240"}
# ensure that there are no line items referencing this product
def ensure_not_referenced_by_any_line_item
if line_items.empty?
return true
else
errors.add(:base, 'Line Items present')
return false
end
end
def image_remote_url=(url_value)
self.image = URI.parse(url_value) unless url_value.blank?
super
end
end
In the asset.rb model:
class Asset < ActiveRecord::Base
attr_accessible :asset
belongs_to :pin
has_attached_file :asset, :styles => { :large => "640x480", :medium => "320x240", :thumb => "100x100>" }
end
in the pins_controller.rb file:
class PinsController < ApplicationController
before_filter :authenticate_user!, except: [:index]
def index
#pins = Pin.order("created_at desc").page(params[:page]).per_page(20)
respond_to do |format|
format.html # index.html.erb
format.json { render json: #pins }
format.js
end
end
def show
#pin = Pin.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #pin }
end
end
def new
#pin = current_user.pins.new
5.times { #pin.assets.build }
respond_to do |format|
format.html # new.html.erb
format.json { render json: #pin }
end
end
def edit
#pin = current_user.pins.find(params[:id])
5.times { #pin.assets.build }
end
def create
#pin = current_user.pins.new(params[:pin])
respond_to do |format|
if #pin.save
format.html { redirect_to #pin, notice: 'Pin was successfully created.' }
format.json { render json: #pin, status: :created, location: #pin }
else
format.html { render action: "new" }
format.json { render json: #pin.errors, status: :unprocessable_entity }
end
end
end
def update
#pin = current_user.pins.find(params[:id])
respond_to do |format|
if #pin.update_attributes(params[:pin])
format.html { redirect_to #pin, notice: 'Pin was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #pin.errors, status: :unprocessable_entity }
end
end
end
def destroy
#pin = current_user.pins.find(params[:id])
#pin.destroy
respond_to do |format|
format.html { redirect_to pins_url }
format.json { head :no_content }
end
end
end
In the _form.html.erb file:
<%= simple_form_for(#pin, :html => { :multipart => true}) do |f| %>
<%= f.full_error :asset_file_size, class: "alert alert-error" %>
<%= f.full_error :asset_content_type, class: "alert alert-error" %>
<%= f.fields_for :assets do |asset_fields| %>
<%= asset_fields.file_field :asset %>
<% end %>
<div class="form-actions">
<%= f.button :submit, class: "btn btn-primary" %>
</div>
<% end %>
Thank you!!!!!
You said the error is:
Can't mass-assign protected attributes: assets_attributes
You don't have this defined in attr_accessible; you have :asset_attributes but not :assets_attributes
Try changing it to the plural version.
On a page I have task listed out. I want to put a form for that task as an update to complete that task. I have the following code as a form_for:
<%= form_for :event, :action => :update, :id => event.id do |f| %>
<%= f.check_box :complete %>
<%= f.submit 'Complete %>
<% end %>
With this code I want it to edit the event with the id in the url and complete the event. What it does it creates a new event instead. Any ideas?
Event Controller:
class EventsController < ApplicationController
layout 'events', :except => 'edit'
# GET /events
# GET /events.json
def index
#events = Event.order("events.initials ASC, events.priroty ASC")
#archived = CompleteEvent.order("complete_events.created_at ASC")
respond_to do |format|
format.html # index.html.erb
format.json { render json: #events }
end
end
# GET /events/1
# GET /events/1.json
def show
#event = Event.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #event }
end
end
# GET /events/new
# GET /events/new.json
def new
#event = Event.new
#users = ['BG', 'BD', 'MB', 'AF', 'RA', 'JM']
#name = ['Brad Garrison', 'Brian Davis', 'Matt Broach', 'Alan McFarland', 'Russell Anderson', 'Jason Milam']
respond_to do |format|
format.html # new.html.erb
format.json { render json: #event }
end
end
# GET /events/1/edit
def edit
#event = Event.find(params[:id])
#users = ['BG', 'BD', 'MB', 'AF', 'RA', 'JM']
#name = ['Brad Garrison', 'Brian Davis', 'Matt Broach', 'Alan McFarland', 'Russell Anderson', 'Jason Milam']
end
# POST /events
# POST /events.json
def create
#event = Event.new(params[:event])
respond_to do |format|
if #event.save
user = #event.name
Notifier.task_created(user).deliver
format.html { redirect_to #event, notice: 'Event was successfully created.' }
format.json { render json: #event, status: :created, location: #event }
else
format.html { render action: "new" }
format.json { render json: #event.errors, status: :unprocessable_entity }
end
end
end
# PUT /events/1
# PUT /events/1.json
def update
#event = Event.find(params[:id])
#save = #event.update_attributes(params[:event])
#complete = CompleteEvent.new(:initials => #event.initials, :name => #event.name, :event_name => #event.event_name, :complete => #event.complete, :event_description => #event.event_description, :comment => #event.comment)
respond_to do |format|
if #event.update_attributes(params[:event])
if #event.complete == true
user = #event.name
#save
#complete
#complete.save
#event.destroy
format.html { redirect_to :controller => :events, :action => :index}
format.json { head :no_content }
elsif #event.complete == false
Notifier.task_updated(user).deliver
format.html { redirect_to :controller => :events, :action => :index}
format.json { head :no_content }
end
end
end
end
# DELETE /events/1
# DELETE /events/1.json
def destroy
#event = Event.find(params[:id])
#event.destroy
respond_to do |format|
format.html { redirect_to events_url }
format.json { head :no_content }
end
end
end
In edit.html.erb (or your partial that is rendered in edit.html.erb) use:
<%= form_for #event do |f| %>
You generally do not need to specify the action, since it is inferred from the URI path, and Rails knows the id for the model object is #event.id.
What I was missing was that my form was in a loop. Therefore when I was calling the form_for #event it couldn't see outside of that loop. I had the function take on the variable of event.
<% #events.each do |event| %>
......
......
<% form_for event do |f| %>
.....
<% end %>
I want to use ajax in my application here is my problem :
I have a income voucher controller and model which receives incomes from various sources.
for this i have a payment_mode model with card, cheque and internet_banking payment option here is my code:
From model:
income_voucher
class IncomeVoucher < ActiveRecord::Base
has_one :payment_mode, :foreign_key => :voucher_id
end
** payment_mode:**
class PaymentMode < ActiveRecord::Base
belongs_to :transactionable, :polymorphic => true
belongs_to :receipt_voucher
end
card_payment:
class CardPayment < ActiveRecord::Base
has_one :payment_mode, :as => :transactionable, :dependent => :destroy
end
similar in cheque and Internet banking model .
My controller:
income_vouchers_controller:
class IncomeVouchersController < ApplicationController
def new
#income_voucher = IncomeVoucher.new
#invoices = current_company.invoices
#income_voucher.build_payment_mode
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #income_voucher }
end
end
def create
#income_voucher = IncomeVoucher.new(params[:income_voucher])
transaction_type = params[:transaction_type]
payment_mode = nil
if transaction_type == 'cheque'
payment = ChequePayment.new(params[:cheque_payment])
payment.amount = #income_voucher.amount
elsif transaction_type == 'card'
payment = CardPayment.new(params[:card_payment])
payment.amount = #income_voucher.amount
elsif transaction_type == 'ibank'
payment = InternetBankingPayment.new(params[:internet_banking_payment])
payment.amount = #income_voucher.amount
else
payment = CashPayment.new
payment.amount = #income_voucher.amount
end
payment_mode = PaymentMode.new
payment_mode.transactionable = payment
#income_voucher.payment_mode = payment_mode
respond_to do |format|
if #income_voucher.save
format.html { redirect_to(#income_voucher, :notice => 'Income voucher was successfully created.') }
format.xml { render :xml => #income_voucher, :status => :created, :location => #income_voucher }
else
format.html { render :action => "new" }
format.xml { render :xml => #income_voucher.errors, :status => :unprocessable_entity }
end
end
end
In my form i did this:
<%= render :partial => "card_payment" %>
<%= render :partial => "cheque_payment" %>
<%= render :partial => "internet_banking_payment" %>
friend till now i am rendering my partials simply as we do in rails but now i want to do this using ajax. I hope you guy's have done this earlier.
thanks
It's simple:
In your javascript (on page, for example:
$.ajax({
url: "your_path",
data: { //params if needed
your_param_name: param,
your_param_name2: param2
}
});
In your routes:
match 'your_path' => 'y_controller#y_method'
In y_controller:
def y_method
# do smth with params[:your_param_name] if needed
respond_to do |format|
format.js
end
end
In your y_method.js.erb:
$('#your-div').html('<%= raw escape_javascript render("cart_payment") %>'); //instead html() may be append()
I was following the tutorial at http://www.logansbailey.com/ and modified it to enable an unregistered person to be able to register with a username, email and password.
I already enabled a logged in user to modify his/her email and password but not the username.
What I want to add is:
1) to enable a logged in user to be able to see/reach his/her username and email,
2) to enable a user with admin_flag set (I handled this in the sql table and created the user) to be able to see/modify all user records.
I modifyed the app/cotrollers/user_controller.rb like this:
class UsersController < ApplicationController
before_filter :is_user, :only => [:index, :show, :edit, :update, :destroy]
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #users }
end
end
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #user }
end
end
def new
#user = User.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #user }
end
end
def edit
end
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
flash[:notice] = 'Registration successful.'
format.html { redirect_to(:controller => 'home', :action => 'tutorial') }
format.xml { render :xml => #user, :status => :created, :location => #user }
else
format.html { render :action => "new" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #user.update_attributes(params[:user])
flash[:notice] = 'Your profile was successfully updated.'
format.html { redirect_to(:controller => 'home', :action => 'index') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to(users_url) }
format.xml { head :ok }
end
end
def is_user
if User.exists?(params[:id])
#user = User.find(params[:id]);
if current_user.admin_flag == true
flash[:notice] = 'Welcome Admin'
end
if !current_user || current_user.id != #user.id
flash[:notice] = 'You do not have access to that page'
redirect_to(:controller => 'home', :action => 'index')
end
else
flash[:notice] = 'You do not have access to that page'
redirect_to(:controller => 'home', :action => 'index')
end
end
end
The file app/models/user.rb is:
class User < ActiveRecord::Base
acts_as_authentic
end
And I can confirm that the admin_flag set user is get correctly since the file app/views/layouts/application.html.erb containing:
<div id="admin">
<% if current_user %>
<% if current_user.admin_flag == true %> |
<%= link_to "Users", users_path %>
<% end %>
<% end %>
</div>
correctly displays the 'Users' link when I log in as the admin.
Now the problem is that I can't get the show all users, edit other users etc.. functionality. As the admin, I can show and modify the admin user just like all the other ordinary users, meaning I can't modify the username, too.
What may be wrong here?
When you added a boolean attribute admin to user in the right way, the Rails should add question-mark method admin? in User model. It's not important but for convenience.
On every method you want to protect from unwanted actions use before_filter:
class UsersController < ApplicationController
before_filter :admin_user, :only => :destroy
before_filter :correct_user, :only => [:edit, :update]
def destroy
end
...
private
def admin_user
redirect_to(root_path) unless current_user.admin?
end
def correct_user
#user = User.find(params[:id])
redirect_to(root_path) unless current_user?(#user) || current_user.admin?
end
end
In views more convenient to use current_user.admin?
<div id="admin">
<% if current_user.admin? %>
<%= link_to "Users", users_path %>
<% end %>
</div>
I have two controllers: projects and stages.
Projects has many stages and stages belongs to projects. I want when you click on the name of the project (i.e. the projects show action), for it to show all the stages related to that project.
How do I do that ?
All of the relevant code can be found below:
Stages Controller
class StagesController < ApplicationController
filter_resource_access
# GET /stages
# GET /stages.xml
def index
#stages = Stage.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #stages }
end
end
# GET /stages/1
# GET /stages/1.xml
def show
#stage = Stage.find(params[:id])
##project = Project.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #stage }
end
end
# GET /stages/new
# GET /stages/new.xml
def new
#stage = Stage.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #stage }
end
end
# GET /stages/1/edit
def edit
#stage = Stage.find(params[:id])
end
# POST /stages
# POST /stages.xml
def create
#stage = current_user.stages.create(params[:stage])
##stage = Stage.new(params[:stage])
respond_to do |format|
if #stage.save
format.html { redirect_to(#stage, :notice => 'Stage was successfully created.') }
format.xml { render :xml => #stage, :status => :created, :location => #stage }
else
format.html { render :action => "new" }
format.xml { render :xml => #stage.errors, :status => :unprocessable_entity }
end
end
end
# PUT /stages/1
# PUT /stages/1.xml
def update
#stage = Stage.find(params[:id])
respond_to do |format|
if #stage.update_attributes(params[:stage])
format.html { redirect_to(#stage, :notice => 'Stage was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #stage.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /stages/1
# DELETE /stages/1.xml
def destroy
#stage = Stage.find(params[:id])
#stage.destroy
respond_to do |format|
format.html { redirect_to(stages_url) }
format.xml { head :ok }
end
end
end
Stages model:
# == Schema Information
# Schema version: 20101124095341
#
# Table name: stages
#
# id :integer not null, primary key
# project_id :integer
# created_at :datetime
# updated_at :datetime
# user_id :integer
# name :string(255)
# stage_num :integer
class Stage < ActiveRecord::Base
belongs_to :projects
#has_and_belongs_to_many :users
has_many :uploads
has_many :comments
end
Projects Model
# == Schema Information
# Schema version: 20101117094659
#
# Table name: projects
#
# id :integer not null, primary key
# name :string(255)
# description :string(255)
# designer_id :integer
# client_id :integer
# notified :boolean
# created_at :datetime
# updated_at :datetime
# user_id :integer
class Project < ActiveRecord::Base
belongs_to :user
has_many :stages
has_many :uploads
has_many :comments
#before_validation { |project| project.user = Authorization.current_user unless project.user }
end
Project Controller
class ProjectsController < ApplicationController
filter_resource_access
# GET /projects
# GET /projects.xml
def index
#projects = current_user.projects
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #projects }
end
end
# GET /projects/1
# GET /projects/1.xml
def show
#project = Project.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #project }
end
end
# GET /projects/new
# GET /projects/new.xml
def new
#project = Project.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #project }
end
end
# GET /projects/1/edit
def edit
#project = Project.find(params[:id])
end
# POST /projects
# POST /projects.xml
def create
#project = current_user.projects.create(params[:project])
respond_to do |format|
if #project.save
format.html { redirect_to(#project, :notice => 'Project was successfully created.') }
format.xml { render :xml => #project, :status => :created, :location => #project }
else
format.html { render :action => "new" }
format.xml { render :xml => #project.errors, :status => :unprocessable_entity }
end
end
end
# PUT /projects/1
# PUT /projects/1.xml
def update
#project = Project.find(params[:id])
respond_to do |format|
if #project.update_attributes(params[:project])
format.html { redirect_to(#project, :notice => 'Project was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #project.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /projects/1
# DELETE /projects/1.xml
def destroy
#project = Project.find(params[:id])
#project.destroy
respond_to do |format|
format.html { redirect_to(projects_url) }
format.xml { head :ok }
end
end
end
Projects Show View
<p id="notice"><%= notice %></p>
<br />
<% #projects.each do |project| %>
<% #stages.each do |stage| %>
<tr>
<td><%= link_to stage.name, stage %> | </td>
<td><%= stage.stage_num %> | </td>
<td><%= link_to 'Show', stage %></td>
<td><%= link_to 'Edit', edit_stage_path(stage) %></td>
<td><%= link_to 'Destroy', stage, :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %>
<% end %>
<% if permitted_to? :create, Stage.new %>
<%= link_to 'New Stage', new_stage_path %>
<% end %><br /><br />
<%= link_to 'Edit', edit_project_path(#project) %> |
<%= link_to 'Back', projects_path %>
There are many ways to do this. The easiest way to accomplish this with your existing code is to change the projects show view page.
replace this:
<% #projects.each do |project| %>
<% #stages.each do |stage| %>
with:
<% #project.stages.each do |stage| %>
Then, you would use the "index" view to show all the projects and the "show" view would be to show project specifics (which would include stages)