i want to create a function into my controller to save a picture uploaded by an admin. I don't want to use plugin or Activerecord, just a function to write the bytes of the picture into the directory app/assets/images/ .
So , when the admin create a new product he puts the picture of the product into the app.
I want to use this function in the action create of the Product Controller.
In this way , before to save in the db the new product , the picture will be saved into the app (not in the db, i want just to write bytes).
I searched on internet and i founded a function to save picture.
I have a strange error : undefined methodread' for "picture.png":String`
Here all my things:
edit.html.erb
<h1>Editing product</h1>
<%= render 'form' ,:multipart => true%>
<%= link_to 'Show', #product %> |
<%= link_to 'Back', products_path %>
_form.html.erb
<%= form_for(#product) do |f| %>
<% if #product.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#product.errors.count, "error") %> prohibited this product from being saved:</h2>
<ul>
<% #product.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :image_url %><br>
<%= f.text_field :image_url %>
</div>
<div class="field">
<%= f.label :price %><br>
<%= f.text_field :price %>
</div>
<div class="field">
<%= f.label :upload %><br>
<%= file_field :upload, :datafile %></p>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
product_controller.rb
def create
name = params[:upload][:datafile]
directory = Rails.root.join('app', 'assets','images')
# create the file path
path = File.join(directory, name)
# write the file
File.open(path, "wb") { |f| f.write(params[:upload][:datafile].read) }
#product = Product.new(product_params)
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: 'Product was successfully created.' }
format.json { render :show, status: :created, location: #product }
else
format.html { render :new }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
thank you for the help.
EDIT: new error
Since you're using form_for, the actual temp file will be in params[:product][:upload]. Try this
Within the _form.html.erb partial, change the file_field line to
<%= file_field :upload %>
Then, within your create action
name = params[:product][:upload].original_filename
directory = Rails.root.join('app', 'assets','images')
# create the file path
path = File.join(directory, name)
# write the file
File.open(path, "wb") { |f| f.write(params[:product][:upload].read) }
Related
I have created a nested form via the cocoon gem, and all is working nicely; however, after filling out the nested form, I can't figure out how to display the nested form data after updating the form in the show.html.erb.
My code:
developments_controller.rb
class DevelopmentsController < ApplicationController
before_action :set_development, only: %i[ show edit update destroy ]
# GET /developments or /developments.json
def index
#developments = Development.all
end
# GET /developments/1 or /developments/1.json
def show
end
# GET /developments/new
def new
#development = Development.new
end
# GET /developments/1/edit
def edit
end
# POST /developments or /developments.json
def create
#development = Development.new(development_params)
respond_to do |format|
if #development.save
format.html { redirect_to #development, notice: "Development was successfully created." }
format.json { render :show, status: :created, location: #development }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #development.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /developments/1 or /developments/1.json
def update
respond_to do |format|
if #development.update(development_params)
format.html { redirect_to #development, notice: "Development was successfully updated." }
format.json { render :show, status: :ok, location: #development }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #development.errors, status: :unprocessable_entity }
end
end
end
# DELETE /developments/1 or /developments/1.json
def destroy
#development.destroy
respond_to do |format|
format.html { redirect_to developments_url, notice: "Development was successfully destroyed." }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_development
#development = Development.find(params[:id])
end
# Only allow a list of trusted parameters through.
def development_params
params.require(:development).permit(:name, :dev_type, :address, :description, :completion, :body_corp, listings_attributes: [:id, :status, :lot_number, :price, :listing_type, :bed, :bath, :car, :land_size, :house_size, :rent, :done, :_destroy])
end
end
development.rb (parent model)
class Development < ApplicationRecord
has_many :listings, inverse_of: :development
accepts_nested_attributes_for :listings, reject_if: :all_blank, allow_destroy: :true
end
listing.rb (child model)
class Listing < ApplicationRecord
belongs_to :development
end
_form.html.erb
<%= form_for #development do |f| %>
<div class="field">
<%= f.label :name %>
<br/>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :dev_type %>
<br/>
<%= f.text_field :dev_type %>
</div>
<div class="field">
<%= f.label :address %>
<br/>
<%= f.text_field :address %>
</div>
<div class="field">
<%= f.label :description %>
<br/>
<%= f.text_field :description %>
</div>
<div class="field">
<%= f.label :completion %>
<br/>
<%= f.text_field :completion %>
</div>
<div class="field">
<%= f.label :body_corp %>
<br/>
<%= f.text_field :body_corp %>
</div>
<h3>Tasks</h3>
<div id="listings">
<%= f.fields_for :listings do |listing| %>
<%= render 'listing_fields', f: listing %>
<% end %>
<div class="links">
<%= link_to_add_association 'add listing', f, :listings %>
</div>
</div>
<%= f.submit %>
<% end %>
_listing_fields.html.erb
<%= form_for #listing do |f| %>
<h3>New Listing</h3>
<div class="nested-fields">
<div class="field">
<%= f.label :status %>
<br/>
<%= f.text_field :status %>
</div>
<div class="field">
<%= f.label :lot_number %>
<br/>
<%= f.text_field :lot_number %>
</div>
<div class="field">
<%= f.label :price %>
<br/>
<%= f.text_field :price %>
</div>
<div class="field">
<%= f.label :listing_type %>
<br/>
<%= f.text_field :listing_type %>
</div>
<div class="field">
<%= f.label :bed %>
<br/>
<%= f.text_field :bed %>
</div>
<div class="field">
<%= f.label :bath %>
<br/>
<%= f.text_field :bath %>
</div>
<div class="field">
<%= f.label :car %>
<br/>
<%= f.text_field :car %>
</div>
<div class="field">
<%= f.label :land_size %>
<br/>
<%= f.text_field :land_size %>
</div>
<div class="field">
<%= f.label :house_size %>
<br/>
<%= f.text_field :house_size %>
</div>
<div class="field">
<%= f.label :rent %>
<br/>
<%= f.text_field :rent %>
</div>
<%= link_to_remove_association "remove listing", f %>
</div>
<%= f.submit %>
<% end %>
show.html.erb
<p id="notice"><%= notice %></p>
<p>
<strong>Name:</strong>
<%= #development.name %>
</p>
<p>
<strong>Dev type:</strong>
<%= #development.dev_type %>
</p>
<p>
<strong>Address:</strong>
<%= #development.address %>
</p>
<p>
<strong>Description:</strong>
<%= #development.description %>
</p>
<p>
<strong>Completion:</strong>
<%= #development.completion %>
</p>
<p>
<strong>Body corp:</strong>
<%= #development.body_corp %>
</p>
<%= link_to 'Edit', edit_development_path(#development) %> |
<%= link_to 'Back', developments_path %>
I've tried calling on a few variations of the code on what's already in show.html.erb, such as #development.listings, #listings and #development.listings_attributes, but whenever I call on a listings_attribute: such as :price, :status etc. from the params in the developments_controller.rb I continually get an error undefined method error. I can't figure out where I'm going wrong, but I know the data is being stored, as it's present when I go to the /edit page on my localhost. I've been following the setup tutorial on https://github.com/nathanvda/cocoon and from this YouTube video: https://www.youtube.com/watch?v=R2iw5BAKBNA which have been great up until displaying the nested form data! The parent data displays no problems at all.
Any help is greatly appreciated!
You can't call the status method on #development.listings, a collection. You should iterate over the collection and call the method on the Listing instance instead.
<% #development.listings.each do |listing| %>
<%= listing.status %>
<% end %>
For some reason validation errors are not showing up.
my form
<%= form_for [#question.category, #question] do |f| %>
<% if #question.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#question.errors.count, "error") %> prohibited this question from being saved:</h2>
<ul>
<% #question.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field panel">
<%= f.label :question_type %><br>
<%= f.select :question_type, [ ["single","single"],["multiple","multiple"] ], selected: f.object.question_type %>
</div>
<div class="field panel">
<%= f.label :description %><br>
<%= f.text_field :description %>
</div>
<div class="field panel">
<%= f.label :image %><br>
<% if #question.image? %>
<div class="explanation-image text-center">
<%= image_tag #question.image_url(:resized) %>
<p>
<label>
<%= f.check_box :remove_image %>
Remove image
</label>
</p>
</div>
<% end %>
<%= f.file_field :image %>
<%= f.hidden_field :image_cache %>
</div>
<div class="field panel">
<%= f.label :explanation %><br>
<%= f.text_area :explanation, size: "30x10" %>
</div>
<div class="field panel">
<%= f.label :link_name %><br>
<%= f.text_field :link_name %>
</div>
<div class="field panel">
<%= f.label :link_url %><br>
<%= f.text_area :link %>
</div>
<div class="field panel">
<%= f.label :video_url %><br>
<%= f.text_area :video_url %>
</div>
<div class="field panel">
<%= f.label :category_id %><br><%= #category.title %>
<%= f.hidden_field :category_id %>
</div>
<div class="actions">
<br>
<%= f.submit 'Submit', class:"button round success" %> <%= link_to 'Back', category_questions_path, class: "button round alert" %>
</div>
<% end %>
this is the model
class Question < ActiveRecord::Base
belongs_to :category
has_many :choices
mount_uploader :image, ImageUploader
validates :description, length: {
minimum: 6
}
validates :link, presence: true
end
and parts of the controller
def edit
#category = Category.find(params[:category_id])
#question = #category.questions.find_by(id: params[:id])
end
def update
respond_to do |format|
if #question.update(question_params)
format.html { redirect_to category_question_url(#question.category, #question), notice: 'Question was successfully updated.' }
format.json { render :show, status: :ok, location: #question }
else
format.html {
#category = Category.find(params[:category_id])
#question = #category.questions.find_by(id: params[:id])
render action: :edit
}
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
the error messages code is directly from the scaffolding. i haven't touched it. if i try to edit a question and save it while lets say link field is empty it will reload the edit action correctly but no error message will pop up.
Any clues?
If it fails to save, you redefine the #question variable, before rendering out the page.
#question = #category.questions.find_by(id: params[:id])
this will delete the object which failed to save and was holding the validation errors, and replace it with the one loaded out of the database. Don't do this. I think if you just delete this line it might work ok.
def update
if #note.update_attributes(note_params)
redirect_to :back, notice: "Note was updated."
else
render :edit
end
end
Is there a way to redirect back twice?
Here you go:
This is where the link for editing goes:
<p id="notice"><%= notice %></p>
<% url = "#{request.protocol}#{request.host_with_port}#{request.fullpath}" %>
<%= link_to 'Create New Page and Return Here', edit_page_path(1, :url => Base64.encode64(url) ) %>
<br>
After submit your url will be something like this:
http://localhost:3000/pages/1/edit?url=aHR0cDovL2xvY2FsaG9zdDozMDAwL2R1bW1pZXM%3D%0A
In the edit form:
I called it pages/_form.html.erb, Pass the URL as a hidden params.
<%= form_for(#page) do |f| %>
<% if #page.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#page.errors.count, "error") %> prohibited this page from being saved:</h2>
<ul>
<% #page.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :permalink %><br>
<%= f.text_field :permalink %>
</div>
<%= hidden_field_tag :url, params[:url].to_s %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
In controller that you have update method, in this case pages_controller.rb, simply Base64 it back and redirect the user:
def update
redirection = nil
if params[:url].present?
redirection = Base64.decode64(params[:url].to_s)
end
if #page.update(page_params)
if redirection.present?
path = redirection
else
path = #page
end
redirect_to path, notice: 'All Done.'
else
render :edit
end
end
Now user updates the form and redirected back to the first show or index page or any page that she is coming from.
Hope this help.
PS: You might want to clean it up a bit and pass the url from the controller, and put some checks on it. So you don't define any var at the view level. In the above code I just tried to solve this issue not really a design pattern oriented :)
This is really simple, but i'm going slightly mad and probably missing something that's staring me in the face. Can anyone help?
Basically, I have a simple each loop that's returning an extra rogue line. Even when there's nothing in the db, I get one line returned!
My show view including the loop is:
<p id="notice"><%= notice %></p>
<p>
<b>Header:</b>
<%= #mailer.header %>
</p>
<p>
<b>Subtext:</b>
<%= #mailer.subtext %>
</p>
<div id="" class="" padding-left: 30px;>
<h3>Mailer Products </h3>
<ol id="mailer-Product-list">
<% #mailer.mailer_products.sort_by { |mailer_products| mailer_products.position }.each do |mailer_product| %>
<%= content_tag_for :li, mailer_product do %>
<%= mailer_product.product.cat_no %>
<% end %>
<% end %>
</ol>
<%#= link_to 'Done', #product, :class => "standard-button" %>
</div>
<%= form_for([#mailer,#mailer.mailer_products.build]) do |f| %>
<div class="field">
<%= f.label :product_id %><br />
<%= f.text_field :product_id %>
</div>
<div class="field">
<%= f.hidden_field :mailer_id, :value => #mailer.id %>
</div>
<div class="actions">
<%= f.submit "Add Product" %>
</div>
<% end %>
<%= link_to 'Edit', edit_mailer_path(#mailer) %> |
<%= link_to 'Back', mailers_path %>
The controller code is:
class MailersController < ApplicationController
def show
#mailer = Mailer.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render :json => #mailer }
end
end
class MailerProductsController < ApplicationController
def index
#mailer_products = MailerProduct.find(:all)
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #mailer_products }
end
end
end
end
Your call to form_for looks like this
form_for([#mailer,#mailer.mailer_products.build]) do |f|
You get an extra blank item because that's what calling .build on mailer_products does: it appends a new instance to the array
When the form is after the loop this doesn't matter, but when things are the other way around the loop will be on the modified array
My usual mistake is adding a <%= instead of a <% on the loop...
<%= #foo.each do |itme| %>
# do stuff
<% end %>
which should be
<% #foo.each do |itme| %>
# do stuff
<% end %>
Double check your tags...
Running Rails 3.2.1.
I went through the "Getting started" guide on the Ruby on Rails site. I have set up a blog post where someone can comment on the posts.
I modified the example to show an error when I enter in comments that don't validate (no name or comment text).
(A post has multiple comments, etc.)
However, how do I have Rails put this problematic comment back in the form, instead of the page?
Here is my create method in the comments controller:
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.build(params[:comment])
respond_to do |format|
if #comment.save
format.html { redirect_to(#post, :notice => 'Comment was successfully created.') }
else
format.html { render 'posts/show' }
end
end
end
Here is my show.html.erb from posts:
<%= render #post %>
<h3>Comments</h3>
<%= render #post.comments %>
<h3>Add a comment</h3>
<%= render "comments/form" %>
<p>
<% if user_signed_in? %>
<%= link_to 'Edit', edit_post_path(#post) %> |
<% end %>
<%= link_to 'Back', posts_path %>
</p>
And here is my comment form partial:
<%= form_for([#post, #post.comments.build]) do |f| %>
<%= render "shared/error_messages", :target => #comment %>
<div class="field">
<%= f.label "Name" %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :body %><br />
<%= f.text_area :body %>
</div>
<div class="actions">
<%= f.submit "Add Comment!" %>
</div>
<% end %>
And here's my comment partial:
<p>
<strong><%= comment.name %></strong><br />
<%= comment.created_at.try(:strftime, "on %A, %B %d %Y at %H:%M:%S") %><br />
<%= simple_format(h(comment.body), :sanitize => true) %>
</p>
In your form when you return from an error.
<% if #comment.errors.any? %>
<div id="errorExplanation">
<h2><%= pluralize(#comment.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>