Hi I am pretty new to Rails, and I managed to get a few classes working together until I tried to use Paperclip.
Everything works fine until I try to upload a picture. I get this error:
undefined method `business_locations_path' for #<#:0x4eecc88>
These are the 2 models:
class Business < ActiveRecord::Base
attr_accessible :bizName, :contact, :email, :ownerName, :signupDate, :website
has_many :businessLocations
end
class BusinessLocation < ActiveRecord::Base
belongs_to :business
attr_accessible :address1, :address2, :contact, :description, :email, :latitude, :longitude, :postal, :price, :mainpic
has_attached_file :mainpic, :styles => {:large => "640x640>", :medium => "320x320>", :thumb => "100x100>"}
end
To create a new location, the path would be something like:
http://localhost:3000/businesses/8/businessLocations/new
The form:
<%
if params[:action] == "new"
urlpath = business_businessLocations_path(#business)
else
if params[:action] == "edit"
urlpath = business_businessLocation_path(#business,#businessLocation)
end
end
%>
<%= form_for #businessLocation, :url=>urlpath, :html =>{ :multipart => true } do |f| %>
...
<div class="field">
<%= f.label :mainpic %><br />
<%= f.file_field :mainpic %>
</div>
The BusinessLocation Controller:
def create
respond_to do |format|
#business = Business.find(params[:business_id])
#businessLocation = #business.businessLocations.build(params[:business_location])
if #businessLocation.save
format.html { redirect_to(business_businessLocation_path(#business,#businessLocation),
:notice => 'Post was successfully created.') }
format.json { render :json => #businessLocation,
:status => :created, :location => #business }
else
format.html { render :action => "new" }
format.json { render :json => #businessLocation.errors,
:status => :unprocessable_entity }
end
end
end
There is no such path business_locations_path because BusinessLocation is nested in Business.
EDIT: here are my rake routes:
business_businessLocations GET /businesses/:business_id/businessLocations(.:format) businessLocations#index
POST /businesses/:business_id/businessLocations(.:format) businessLocations#create
new_business_businessLocation GET /businesses/:business_id/businessLocations/new(.:format) businessLocations#new
edit_business_businessLocation GET /businesses/:business_id/businessLocations/:id/edit(.:format) businessLocations#edit
business_businessLocation GET /businesses/:business_id/businessLocations/:id(.:format) businessLocations#show
PUT /businesses/:business_id/businessLocations/:id(.:format) businessLocations#update
DELETE /businesses/:business_id/businessLocations/:id(.:format) businessLocations#destroy
businesses GET /businesses(.:format)
businesses#index
POST /businesses(.:format)
businesses#create
new_business GET /businesses/new(.:format)
businesses#new
edit_business GET /businesses/:id/edit(.:format)
businesses#edit
business GET /businesses/:id(.:format)
businesses#show
PUT /businesses/:id(.:format)
businesses#update
DELETE /businesses/:id(.:format)
businesses#destroy
In your controller, you have the create action set to redirect to business_businessLocation_path. This is autogenerated by whatever you used to genereate your nested scaffold. Fixing this will probably fix all your problems.
Related
So, I'm getting the following error when trying to visit the films page on my app:
ActionController::ParameterMissing (param is missing or the value is empty: film):
2014-07-24T22:04:44.622356+00:00 app[web.1]: app/controllers/saas_admin/films_controller.rb:54:in `permitted_params'
See my films controller code below
films_controller.rb
class SaasAdmin::FilmsController < SaasAdminController
inherit_resources
belongs_to :studio, :finder => :find_by_id!, :param => :studio_id, :class_name => Studio
before_filter :set_sort_fields, :only => :edit
before_filter :build_collections, :only => [:new, :create, :edit, :update]
def create
create! { parent_path(parent.id) } # Redirect to studio in case studio_id is changed
end
def update
#film = Film.find_by_permalink(params[:id])
respond_to do |format|
if #film.update(permitted_params)
format.html { redirect_to saas_admin_studio_path(#film.studio), notice: 'Film was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #film.errors, status: :unprocessable_entity }
end
end
end
def index
redirect_to parent_path(parent.id)
end
def show
#clips = resource.clips.paginate(:page => params[:page], :per_page => 30, :order => 'clips.position')
end
protected
def resource
# #film ||= end_of_association_chain.find_by_permalink!(params[:id])
#film ||= end_of_association_chain.find_by_permalink!(params[:id])
end
def collection
#films ||= end_of_association_chain.paginate(:page => params[:page], :per_page => 30, :order => 'films.created_at')
end
def set_sort_fields
resource.sort_name = '' if resource.name == resource.sort_name
end
def build_collections
#studios ||= Studio.find(:all)
end
def permitted_params
params.require(:film).permit(:name, :sort_name, :description, :short_description, :meta_data,
:poster, :amazon_link, :active, :trackable, :country_ids => [])
end
end
What might this be? I've been trying to figure it out for a bit but perhaps a fresh set of eyes will find it's something rather simple.
Cheers!
Edit
Here's the view code for films/new.html.erb
<h1><%= #page_title = "New #{resource_class}" %></h1>
<%= form_for resource, :url => collection_path, :html => { :multipart => true } do |f| -%>
<%= render :partial => "form", :locals => { :f => f } %>
<% end -%>
<% content_for :sidebar do %>
<%= render :partial => "saas_admin/shared/sidebar" %>
<% end %>
and films/edit.html.erb
<h1><%= #page_title = "Edit #{resource_class}" %></h1>
<%= form_for resource, :url => saas_admin_studio_film_path(parent, resource), :html => { :multipart => true } do |f| -%>
<%= render :partial => "form", :locals => { :f => f } %>
<% end -%>
<% content_for :sidebar do %>
<%= render :partial => "saas_admin/shared/sidebar" %>
<% end %>
Edit 2
For reference here is how the permitted params was defined when it was working:
def permitted_params
{:film => params.fetch(:film, {}).permit(
:name, :sort_name, :description, :short_description, :meta_data,
:poster, :amazon_link, :active, :trackable)}
end
I have got this problem too when I use Angular JS form to send data to backend Rails 4. When I did not fill anything in angular js form, the error will show ActionController::ParameterMissing (param is missing or the value is empty:.
I fix it by adding params.fetch(:film, {}) the strong parameter into:
params.fetch(:film, {}).permit(:name, :sort_name, :description, :short_description, :meta_data,
:poster, :amazon_link, :active, :trackable, :country_ids => [])
I refer to code example to avoid ActionController::ParameterMissing (param is missing or the value is empty: film)
I hope this will help you.
Why not use so:
def creation_params
params.permit(:film)
end
It working for me! ;)
This is happening because you have specified to require 'film' in your parameters through strong_params (specified above in your permitted_params code).
Whatever the view side is doing (whether its a link or a form/etc.), its not passing its parameters nested under 'film'
eg.) if you were to raise params.inspect in the controller action, you would see that there is no node for "film".
Most likely what is wrong is that the form code you have on the view side is not set to nest these parameters properly, are you using a form_tag for example?
Getting this error in posts>show when I try to load up a form.
The form is for users to send messages to each other. Grateful for any feedback!
Thanks.
NoMethodError in Posts#show
Showing /Users/fkhalid2008/loand/app/views/posts/show.html.erb where line #1 raised:
undefined method `user' for #<Post:0x12e2ae930>
Extracted source (around line #1):
1: <%= form_remote_tag (:update => 'message', :url => {:controller => 'main', :action => 'send_message', :user_id => #post.user.id}) do %>
2: <br>
3: <br />
4: <br />
POSTS>SHOW VIEW
<%= form_remote_tag (:update => 'message', :url => {:controller => 'main', :action => 'send_message', :user_id => #post.user.id}) do %>
<br>
<br />
<br />
<div class="field">
Hello! My name is <%= f.text_field :subject %> and I'm contacting you in response to your ad. I'm interested in learning more so get in touch! Here's my contact details: <%= f.text_field :body %>.
</div>
<button type="submit" class="btn span6 large">Submit</button>
<% end %>
POSTS CONTROLLER
def new
#post = Post.new
respond_to do |format|
format.html # new.html.erb
format.json { render :json => #post }
end
end
def edit
#post = Post.find(params[:id])
end
def create
#post = Post.new(params[:post])
respond_to do |format|
if verify_recaptcha && #post.save
format.html { redirect_to :action=> "index"}
format.json { render :json => #post, :status => :created, :location => #post }
else
format.html { render :action => "new" }
format.json { render :json => #post.errors, :status => :unprocessable_entity }
end
end
end
MAIN CONTROLLER
class MainController < ApplicationController
def send_message
message = Message.new
message.subject = params[:subject]
message.body = params[:message]
message.sender = User.find session[:user]
message.recipient = User.find params[:user_id]
if message.save
ContactMailer.deliver_message_email message.recipient.email, message.id, request.host
return redirect_to "/posts"
else
render :text => "Hmm. Something seems to be wrong...let me look into it"
end
CONTACT MAILER
class ContactMailer < ActionMailer::Base
def message_email (recipient, id, host)
recipients [ recipient ]
subject "Weddoo: You have received a new message"
from "admin#weddoo.com"
bcc ["admin#weddoo.com"]
content_type "text/html"
body :message_id => id, :host => host
sent_on Time.now
end
end
end
ROUTES.RB
Mysalary::Application.routes.draw do
resources :users do
resources :messages
end
resources :profiles
resources :pages
resources :posts
get "pages/home"
get "pages/about"
get "pages/legal"
get "pages/feedback"
root :to => 'posts#new'
end
POST MODEL
class Post < ActiveRecord::Base
attr_accessible :title, :job, :location, :salary
validates :title, :job, :location, :salary, :presence => true
validates :salary, :numericality => {:greater_than_or_equal_to => 1}
default_scope :order => 'posts.created_at DESC'
end
The error is saying there is no method user on the Post model. It points you directly to the first line.
<%= form_remote_tag (:update => 'message', :url => {:controller => 'main', :action => 'send_message', :user_id => #post.user.id}) do %>
so I'd say
#post.user.id is your problem statement, that model doesn't have a method user but it's hard to know for sure without seeing the Post model.
I think you have missed to add relationship.
class Post < ActiveRecord::Base
belongs_to :user
end
I am trying to create URL upload with paperclip.
I have followed this guide: http://trevorturk.com/2008/12/11/easy-upload-via-url-with-paperclip/
The problem is that nothing gets uploaded when I use the image_url fields. I know my code isnt very dry therefor it would be nice if someone had, some tips to rewrite the code.
I have 2 attached images and therefor 2 image URLs.
My konkurrancers table:
photo_file_name varchar(255)
photo_content_type varchar(255)
photo_file_size int(11)
photo_updated_at datetime
photo2_file_name varchar(255)
photo2_content_type varchar(255)
photo2_file_size int(11)
photo2_updated_at datetime
image_remote_url varchar(255)
image_remote_url_2 varchar(255)
My konkurrancer model:
class Konkurrancer < ActiveRecord::Base
has_attached_file :photo,
:url => "/public/images/billeder/photo/:id/:basename.:extension",
:path => ":rails_root/public/images/billeder/photo/:id/:basename.:extension"
has_attached_file :photo2,
:url => "/public/images/billeder/photo2/:id/:basename.:extension",
:path => ":rails_root/public/images/billeder/photo2/:id/:basename.:extension"
before_validation :download_remote_image, :if => :image_url_provided?
before_validation :download_remote_image_2, :if => :image_url_2_provided?
validates_presence_of :image_remote_url, :if => :image_url_provided?, :message => 'is invalid or inaccessible'
validates_presence_of :image_remote_url_2, :if => :image_url_2_provided?, :message => 'is invalid or inaccessible'
private
def image_url_provided?
!self.image_url.blank?
end
def image_url_2_provided?
!self.image_url_2.blank?
end
def download_remote_image
self.photo = do_download_remote_image
self.image_remote_url = image_url
end
def download_remote_image_2
self.photo2 = do_download_remote_image_2
self.image_remote_url_2 = image_url_2
end
def do_download_remote_image
io = open(URI.parse(image_url))
def io.original_filename; base_uri.path.split('/').last; end
io.original_filename.blank? ? nil : io
rescue # catch url errors with validations instead of exceptions (Errno::ENOENT, OpenURI::HTTPError, etc...)
end
def do_download_remote_image_2
io = open(URI.parse(image_url_2))
def io.original_filename; base_uri.path.split('/').last; end
io.original_filename.blank? ? nil : io
rescue # catch url errors with validations instead of exceptions (Errno::ENOENT, OpenURI::HTTPError, etc...)
end
end
My controller create action:
def create
#konkurrancer = Konkurrancer.new(params[:konkurrancer])
respond_to do |format|
if #konkurrancer.save
format.html { redirect_to(:admin_konkurrancers, :notice => 'Konkurrancer was successfully created.') }
format.xml { render :xml => :admin_konkurrancers, :status => :created, :location => #konkurrancer }
else
format.html { render :action => "new" }
format.xml { render :xml => #konkurrancer.errors, :status => :unprocessable_entity }
end
end
end
My form:
<%= simple_form_for [:admin, #konkurrancer], :html => { :multipart => true } do |f| %>
<%= f.label :upload_125x125 %>
<%= f.file_field :photo, :label => '125x125', :style => 'width:250;' %>
<%= f.input :image_url_2, :label => 'URL 125x125', :style => 'width:250;' %>
<%= f.label :upload_460x60 %>
<%= f.file_field :photo2, :label => '460x58', :style => 'width:250;' %>
<%= f.button :submit, :value => 'Create konkurrence' %>
<% end %>
In the latest version of paperclip (pull request has been merged but i'm not sure about the release) paperclip > 3.1.3 (maybe 3.2 is upcoming; maybe 3.1.4) this is become even easier.
self.photo = URI.parse("http://something.com/blah/image.png")
The above should take care of download/tempfile stuff/filename and filecontent type.
Enjoy! :)
To fix the problem of an repetitive model, you'll want to instead create a separate class for your photos that stores a foreign key to the konkurrence:
class Photo < ActiveRecord::Base
has_attached_file ...
belongs_to :konkurrence
...
end
class Konkurrence < ActiveRecord::Base
has_many :photos, :dependent => :destroy
accepts_nested_attributes_for :photos, :allow_destroy => true
...
end
Also, I think you're trying to download a remote image from a URL and then save this into Paperclip. Using open-uri (as I believe you already are), you can do this like so:
# open a tempfile using the last 14 chars of the filename
t = Tempfile.new(image_url.parameterize.slice(-14, 14))
t.write(open(image_url).read)
t.flush
t # return the File. You can then set the paperclip attribute to this File, eg, self.photo = t
This will save your URL as a temporary file which you can then pass on to Paperclip for regular processing.
I'm working on a website that allows people who run bed and breakfast businesses to post their accommodations.
I would like to require that they include a "profile image" of the accommodation when they post it, but I also want to give them the option to add more images later (this will be developed after).
I thought the best thing to do would be to use the Paperclip gem and have a Accommodation and a Photo in my application, the later belonging to the first as an association.
A new Photo record is created when they create an Accommodation. It has both id and accommodation_id attributes. However, the image is never uploaded and none of the Paperclip attributes get set (image_file_name: nil, image_content_type: nil, image_file_size: nil), so I get Paperclip's "missing" photo.
Any ideas on this one? It's been keeping me stuck for a few days now.
Accommodation
models/accommodation.rb
class Accommodation < ActiveRecord::Base
validates_presence_of :title, :description, :photo, :thing, :location
attr_accessible :title, :description, :thing, :borough, :location, :spaces, :price
has_one :photo
end
controllers/accommodation_controller.erb
class AccommodationsController < ApplicationController
before_filter :login_required, :only => {:new, :edit}
uses_tiny_mce ( :options => {
:theme => 'advanced',
:theme_advanced_toolbar_location => 'top',
:theme_advanced_toolbar_align => 'left',
:theme_advanced_buttons1 => 'bold,italic,underline,bullist,numlist,separator,undo,redo',
:theme_advanced_buttons2 => '',
:theme_advanced_buttons3 => ''
})
def index
#accommodations = Accommodation.all
end
def show
#accommodation = Accommodation.find(params[:id])
end
def new
#accommodation = Accommodation.new
end
def create
#accommodation = Accommodation.new(params[:accommodation])
#accommodation.photo = Photo.new(params[:photo])
#accommodation.user_id = current_user.id
if #accommodation.save
flash[:notice] = "Successfully created your accommodation."
render :action => 'show'
else
render :action => 'new'
end
end
def edit
#accommodation = Accommodation.find(params[:id])
end
def update
#accommodation = Accommodation.find(params[:id])
if #accommodation.update_attributes(params[:accommodation])
flash[:notice] = "Successfully updated accommodation."
render :action => 'show'
else
render :action => 'edit'
end
end
def destroy
#accommodation = Accommodation.find(params[:id])
#accommodation.destroy
flash[:notice] = "Successfully destroyed accommodation."
redirect_to :inkeep
end
end
views/accommodations/_form.html.erb
<%= form_for #accommodation, :html => {:multipart => true} do |f| %>
<%= f.error_messages %>
<p>
Title<br />
<%= f.text_field :title, :size => 60 %>
</p>
<p>
Description<br />
<%= f.text_area :description, :rows => 17, :cols => 75, :class => "mceEditor" %>
</p>
<p>
Photo<br />
<%= f.file_field :photo %>
</p>
[... snip ...]
<p><%= f.submit %></p>
<% end %>
Photo
The controller and views are still the same as when Rails generated them.
models/photo.erb
class Photo < ActiveRecord::Base
attr_accessible :image_file_name, :image_content_type, :image_file_size
belongs_to :accommodation
has_attached_file :image,
:styles => {
:thumb=> "100x100#",
:small => "150x150>" }
end
To create an upload with paperclip, you need to use the name you provided for the has_attached_file line, on the model you defined it on. In your case, this will result in this view code:
<%= form_for #accommodation, :html => { :multipart => true } do |f| %>
<%= f.fields_for :photo do |photo_fields| %>
<p>
Photo<br />
<%= photo_fields.file_field :image %>
</p>
<% end %>
<% end %>
In the controller:
class AccommodationsController < ApplicationController
# also protect create and update actions!
before_filter :login_required, :only => [ :new, :create, :edit, :update ]
def new
# always make objects through their owner
#accommodation = current_user.accommodations.build
#accommodation.build_photo
end
def create
#accommodation = current_user.accommodations.build(params[:accommodation])
if #accommodation.save
# always redirect after successful save/update
redirect_to #accommodation
else
render :new
end
end
end
Tell Rails to handle the nested form:
class Accommodation
has_one :photo
accepts_nested_attributes :photo
attr_accessible :photo_attributes, :title, :description, :etc
end
And make sure to set the accessible attributes right in your photo model:
class Photo
attr_accessible :image # individual attributes such as image_file_name shouldn't be accessible
has_attached_file :image, :styles => "etc"
end
Be sure to watch your log files to spot things that are protected by attr_accessible, but still are in your form.
I'm trying to use rails nested form_for helper, but I am getting the following error:
BlogPage(#49859550) expected, got Array(#31117360)
Here are my model objects:
class Blog < ActiveRecord::Base
# Table Configuration
set_table_name "blog"
# Model Configuration
belongs_to :item
has_many :blog_pages
accepts_nested_attributes_for :blog_pages, :allow_destroy => true
end
class BlogPage < ActiveRecord::Base
# Table Configuration
set_table_name "blog_page"
# Model Configuration
belongs_to :blog
end
Here is the form I generated (left out unnecessary HTML):
<% form_for :blog, :url => { :action => :create } do |blog_form| %>
<%= blog_form.text_field :title, :style => "width: 400px" %>
<% blog_form.fields_for :blog_pages do |page_fields| %>
<% #blog.blog_pages.each do |page| %>
<%= page_fields.text_area :content, :style => "width: 100%",
:cols => "10", :rows => "20" %>
<% end %>
<% end %>
<% end %>
Here are the parameters that are sent to the controller:
{"commit"=>"Save",
"blog"=>{"blog_pages"=>{"content"=>"This is the new blog entries contents."},
"title"=>"This is a new blog entry.",
"complete"=>"1"},
"authenticity_token"=>"T1Pr1g9e2AjEMyjtMjLi/ocrDLXzlw6meWoLW5LvFzc="}
Here is the BlogsController with the create action that gets executed:
class BlogsController < ApplicationController
def new
#blog = Blog.new # This is the line where the error gets thrown.
# Set up a page for the new blog so the view is displayed properly.
#blog.blog_pages[0] = BlogPage.new
#blog.blog_pages[0].page_number = 1
respond_to do |format|
format.html # Goes to the new.html.erb view.
format.xml { render :xml => #blog }
format.js { render :layout => false}
end
end
def create
#blog = Blog.new(params[:blog])
respond_to do |format|
if #blog.save
render :action => :show
else
flash[:notice] = "Error occurred while saving the blog entry."
render :action => :new
end
end
end
end
If anyone can help me with this I would greatly appreciate it. I'm still pretty new to ruby and the rails framework and couldn't solve the problem on my own by googling.
Thanks.
Have you seen this?
http://media.pragprog.com/titles/fr_arr/multiple_models_one_form.pdf
Change your form to this:
<% form_for :blog, :url => { :action => :create } do |blog_form| %>
<%= blog_form.text_field :title, :style => "width: 400px" %>
<% blog_form.fields_for :blog_pages do |page_fields| %>
<%= page_fields.text_area :content, :style => "width: 100%",
:cols => "10", :rows => "20" %>
<% end %>
<% end %>
If you use fields_for it iterates over blog_pages automaticaly. However I'm not sure if this caused errors.