Paperclip error - Can't mass-assign protected attributes - ruby-on-rails-3

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.

Related

form_for update method

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 %>

Update action fire an insert query?

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.

failed to test create action

I am playing with rails 3.0.6 with ruby 1.9.2,
the app is working on browser but not in testing..
1) I created a new rails application by "rails new myapp"
2) Generate a scaffold "rails generate scaffold user username:string hashed_password:string salt:string"
3) after that, i changed the users_controller a bit
# POST /users
# POST /users.xml
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
// change #user to usrs_url
format.html { redirect_to(users_url, :notice => "User #{#user.username} was successfully created.") }
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
# PUT /users/1
# PUT /users/1.xml
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
// change #user to usrs_url
format.html { redirect_to(users_url, :notice => "User #{#user.username} was successfully updated.") }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
4) so i try to modify tests as well:
setup do
#input_attributes = {
:username => 'username#goodmail.com',
:password => 'secret',
:password_confirmation => 'secret'
}
#user = users(:one)
end
test "should create user" do
assert_difference('User.count') do
post :create, :user => #input_attributes
end
assert_redirected_to users_path
end
test "should update user" do
put :update, :id => #user.to_param, :user => #input_attributes
assert_redirected_to users_path
end
But the create and update tests failed
Can anyone let me know what had i done wrong?
Thanks
Loaded suite C:/Ruby192/lib/ruby/1.9.1/rake/rake_test_loader
Started
F.....F
Finished in 5.628874 seconds.
1) Failure:
test_should_create_user(UsersControllerTest) [test/functional/users_controller_test.rb:26]:
"User.count" didn't change by 1.
<3> expected but was
<2>.
2) Failure:
test_should_update_user(UsersControllerTest) [test/functional/users_controller_test.rb:45]:
Expected block to return true value.
7 tests, 9 assertions, 2 failures, 0 errors, 0 skips
require 'digest/sha2'
class User < ActiveRecord::Base
validates :username, :presence => true, :uniqueness => true
validates_format_of :username, :with => /\A^[^\r\n# ][^\r\n# ]+#[^\r\n# ]+[.][^\r\n#. ]+$\Z/i
#password is a fake field
validates :password, :confirmation => true
validate :password_must_be_present
attr_accessor :password_confirmation
attr_reader :password
def password=(password)
if password.present?
generate_salt
self.hashed_password = self.class.encrypt_password(password, salt)
end
end
class << self
def encrypt_password(password, salt)
Digest::SHA2.hexdigest(password + "shrimpy" + salt)
end
def authenticate(username, password)
if user = find_by_username(username)
if user.hashed_password == encrypt_password(password, user.salt)
user
end
end
end
end
private
def password_must_be_present
errors.add(:password, "Missing password") unless hashed_password.present?
end
def generate_salt
self.salt = self.object_id.to_s + rand.to_s
end
end
assert_redirected_to user_path is singular. You probably don't even have a singular user resource route defined. What you want there is probably assert_redirected_to users_path with a plural users.

Howto assign an ordinary user as superuser or admin

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>

How do I show all the stages (one model) that belong to a project (another model) in Rails 3?

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)