I'm using Carrierwave with Rails to upload and display images. I've been using it for articles and other parts of my site without a problem but for some reason it's not working for the model I just created. I can see the space for the image tag rendered without the image and then disappear quickly when the page loads. Nothing like this has occurred until I tried it with this model which isn't much different from my other models:
class Ad < ActiveRecord::Base
validates_numericality_of :zip_code
validates_presence_of :image, :advertiser
mount_uploader :image, ImageUploader
end
My create and index actions:
def create
#ad = Ad.new(params[:ad].permit(:image, :advertiser, :zip_code))
if #ad.save
redirect_to :back
else
flash[:error] = "Invalid input"
redirect_to :back
end
end
def index
#new_ad = Ad.new
#ads = Ad.all.reverse
end
My _new partial:
<div id="card">
<%= form_for #new_ad, html: {multipart: true, "data-ajax" => false} do |f| %>
<p>
<%= f.file_field :image %>
</p>
<p>
<%= f.text_field :advertiser, placeholder: "Advertiser" %>
</p>
<p>
<%= f.text_field :zip_code, placeholder: "Zip code" %>
</p>
<p>
<%= f.submit "Upload" %>
</p>
<% end %>
</div></br>
My index view:
<%= render "new" %>
<% for ad in #ads %>
<div id="card">
<div align="center">
<%= image_tag ad.image %>
<%= ad.advertiser %>
<%= ad.zip_code %>
</div>
</div></br>
<% end %>
As per my understanding problem is with your index view.
<%= image_tag ad.image %>
you are using ad.image this will return you imageuploader object not image path. So instead of using ad.image you can use ad.image.url(relative path) or ad.image.current_path(absolute path)
<%= image_tag ad.image.url %>
Related
I am using a theme that has very specific layouts and I wanted to make a failsafe way to you rails forms.
I have a layout app/views/shared/forms/fields/_layout.html.erb
<div class="js-form-message mb-4">
<div class="js-focus-state input-group u-form">
<div class="input-group g-brd-primary--focus">
<%= yield(:field) %>
</div>
</div>
</div>
And I have two partials.
1-st partial: app/views/shared/forms/fields/_email.html.erb
<% form = locals[:form] %>
<% locals[:required] = locals[:required].nil? ? true : locals[:required] %>
<% locals[:placeholder] = locals[:placeholder] || t('forms.shared.email.placeholder') %>
<%= render layout: "shared/forms/fields/layout", locals: locals do %>
<% content_for(:field) do %>
<%= form.email_field :email,
placeholder: locals[:placeholder],
class: "form-control g-py-15 g-px-15",
"data-error-class"=>"u-has-error-v1-3",
"data-success-class"=>"u-has-success-v1-2",
"data-msg-email" => t('forms.shared.email.validate'),
"data-msg" => t('forms.shared.required'),
autofocus: locals[:autofocus],
required: locals[:required] %>
<% end %>
<% end %>
2-nd partial: app/views/shared/forms/fields/_login.html.erb
<% form = locals[:form] %>
<% locals[:required] = locals[:required].nil? ? true : locals[:required] %>
<% locals[:placeholder] = locals[:placeholder] || t('forms.shared.login.placeholder') %>
<%= render layout: "shared/forms/fields/layout", locals: locals do %>
<% content_for(:field) do %>
<%= form.email_field :login,
placeholder: locals[:placeholder],
class: "form-control g-py-15 g-px-15",
"data-error-class"=>"u-has-error-v1-3",
"data-success-class"=>"u-has-success-v1-2",
"data-msg" => t('forms.shared.required'),
autofocus: locals[:autofocus],
required: locals[:required] %>
<% end %>
<% end %>
And when I do this:
<%= render "shared/forms/fields/email", locals: {form: f} %>
<%= render "shared/forms/fields/login", locals: {form: f} %>
I get
Email Field
Email Field/Login Field
I found out that content_for 'appends' the block that you give it and then when I yield the whole block is returned.
The first time there is nothing in content_for(:field) and it appends to it Email Field. But the second time it does not clear its content and just appends Login Field to it.
I am thinking of adding additional complexity to layout.html.erb so just keeping it inline isn't an option.
Is there a way to tell to the layout only to yield the 'newest' value of content_for.
EDIT:
I wrote a method to flush after an yield, suggesting that the same key would be used again:
def yield_and_flush!(content_key)
view_flow.content.delete(content_key)
end
content_for has flush option to reset previous content:
<% content_for :field, flush: true do %>
new content here
<% end %>
The solution was this to write an yield_and_flush! method. I saw the solution here
def yield_and_flush!(content_key)
view_flow.content.delete(content_key)
end
new.html is a registration form ,which creates tutor account .
It involves error handling . _error_messages.html.erb is the file which handles the error ,like should be filling in all text fields .
e.g , showing :
`
The form contains 3 errors.
Name can't be blank
Password confirmation can't be blank
Password confirmation doesn't match Password
However ,when submits the form without any input in new.html ,it shows the error
Missing template tutors/register, application/register with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :coffee, :jbuilder]}. Searched in: * "C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/web-console-2.0.0/lib/action_dispatch/templates" * "D:/Sites/abc/app/views"
new.html.erb
<% provide(:title, 'Registeration') %>
<h1>Tutor Registration</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(#tutor) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.label :email %>
<%= f.text_field :email, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.label :password_confirmation, "Confirm Password" %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
<%= f.label :gender %>
<%= f.select(:gender, ['Male', 'Female'] , class: 'form-control' )%>
<%= f.label :tutor_education_level %>
<%= f.select(:education_level, ['Bachelor', 'Master', 'Doctor'] , class: 'form-control' )%>
<%= f.label :tutor_institution %>
<%= f.text_field :institution, class: 'form-control' %>
<%= f.label :tutorial_experience %>
<%= f.text_field :experience, class: 'form-control' %>
<%= f.label :tutor_preferred_district %>
<%= f.text_field :district, class: 'form-control' %>
<%= f.label :tutor_preferred_subject %>
<%= f.text_field :subject, class: 'form-control' %>
<%= f.label :tutor_required_student_level %>
<%= f.select(:student_level, ['P1-P3', 'P4-P6', 'S1-S3', 'S4-S6'] , class: 'form-control' )%>
<%= f.submit "Create tutor's account", class: "btn btn-primary" %>
<% end %>
</div>
</div>
views/shared/_error_messages.html.erb
<% if #tutor.errors.any? %>
<div id="error_explanation">
<div class="alert alert-danger">
The form contains <%= pluralize(#tutor.errors.count, "error") %>.
</div>
<ul>
<% #tutor.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
Tutor -controller
class TutorsController < ApplicationController
before_action :logged_in_tutor, only: [:edit, :update]
before_action :correct_tutor, only: [:edit, :update]
def index
#tutors = Tutor.all
end
def show
#tutor = Tutor.find(params[:id])
end
def new
#tutor = Tutor.new
end
def create
#tutor = Tutor.new(tutor_params)
if #tutor.save
log_in #tutor
flash[:success] = "Congratulations! Your registration is successful!"
redirect_to #tutor
else
render 'register'
end
end
def edit
#tutor = Tutor.find(params[:id])
end
def update
if #tutor.update_attributes(tutor_params)
flash[:success] = "Profile updated successfuly!"
redirect_to #tutor
else
render 'edit'
end
end
# Handle sign-up failure, to redirect the tutor to the registeration form again
def tutor_params
params.require(:tutor).permit(:name, :email, :password, :password_confirmation, :address,:gender ,:education_level,:institution,:exprience,:district,:subject,:student_level)
end
def logged_in_tutor
unless logged_in?
store_location
flash[:danger] = "Please log in."
redirect_to login_url
end
end
def correct_tutor
#tutor = Tutor.find(params[:id])
redirect_to(root_url) unless current_tutor?(#tutor)
end
end
When you submit the form, request sends to the create action:
def create
#tutor = Tutor.new(tutor_params)
if #tutor.save
# if #tutor valid save it and redirect to show action
redirect_to #tutor
else
# else render the register template(or action)
render 'register'
end
end
In the create action there is a conditional if, in the first case all is good, #tutor has been saved and Rails call redirect to show action, otherwise Rails trying to render register template which is not exists(the errors claims about it). To resolve that issue create register template with desired html code which should run if #tutor isn't saved.
Yes, I already checked here. It didn't work.
Rails: 5.0.2
Ruby: 2.4.0
I have a collection for comments and every time it is called, it renders one time too many and an empty comment always appears below others and when no comments exist, one empty one still renders.
Here is the code:
View
<h2>Add a comment:</h2>
<%= render 'comments/form' %>
<h2>Comments</h2>
<%= render #video.comments || "There are no comments yet." %>
Form partial
<%= form_for([#video, #video.comments.new]) do |f| %>
<p>
<%= f.label :name %><br>
<%= f.text_field :commenter %>
</p>
<p>
<%= f.label :body %><br>
<%= f.text_area :body %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
Comment partial
<p>
<strong>Name:</strong>
<%= comment.commenter %>
</p>
<p>
<strong>Comment:</strong>
<%= comment.body %>
</p>
<p>
<%= link_to 'Destroy Comment', [comment.video, comment],
method: :delete,
data: { confirm: 'Are you sure?' } %>
</p>
Controller
def create
#video = Video.find(params[:video_id])
#comment = #video.comments.create(comment_params)
redirect_to video_path(#video)
end
def destroy
#video = Video.find(params[:video_id])
#comment = #video.comments.find(params[:id])
#comment.destroy
redirect_to video_path(#video)
end
private
def comment_params
params.require(:comment).permit(:commenter, :body)
end
Does anyone know why this would render the partial an extra time?
You may try to call .scope on comments association:
<%= render #video.comments.scope || "There are no comments yet." %>
A beginner in Ruby here!
I am trying to create a Soundcloud clone on ruby.
When I try to upload an audio file i get the error:
1 error prohibited this song from being saved:
Audio has contents that are not what they are reported to be
controller: song.rb
class Song < ActiveRecord::Base
belongs_to :user
has_attached_file :audio,
:url => "/assets/:class/:id/:attachment/:basename.:extension",
:path => ":rails_root/public/assets/:class/:id/:attachment/:basename.:extension"
validates_attachment :audio,
:content_type => { :content_type => ["audio/mpeg", "audio/mp3"] },
:file_name => { :matches => [/mp3\Z/] }
_form.html.erb
<%= form_for(#song) do |f| %>
<% if #song.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#song.errors.count, "error") %> prohibited this song from being saved:</h2>
<ul>
<% #song.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :audio %><br>
<%= f.file_field :audio%>
</div>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_field :description %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
show.html.erb
<p id="notice"><%= notice %></p>
<p>
<strong>Audio:</strong>
<%= #song.audio.url %>
</p>
<p>
<strong>Title:</strong>
<%= #song.title %>
</p>
<%= link_to 'Edit', edit_song_path(#song) %> |
<%= link_to 'Back', songs_path %>
In my experience with this problem, image data in the mp3's metadata (i.e. - an album cover) was the critical factor. The image data triggers the content type spoofing mechanism and the record will fail validation. To remove the image metadata, I opened the mp3 with Audacity, and exported it to a new file, which will not include image metadata because Audacity doesn't seem to include this automatically.
I don't know which is the best or right way to make something, so I'm looking for suggestions.
Stage:
I am using Rails 3 to make some web app.
Imaging two models: Canvas and Zone.
A canvas object intents to be a square in which there will be four zone's (north, south, east and west).
Each zone has these attributes: text:string and rgb_color:string.
I want to render a HTML form in which user must capture a Canvas registry, in other words, in this form will have four groups of zones fields.
Problem:
How can I capture all of them in one HTML form?
If I would have only one zone I can do something like this:
<%= form_for(#zone) do |f| %>
<div class="field">
<%= f.label :text %><br />
<%= f.text_field :text %>
</div>
<div class="field">
<%= f.label :rgb_color %><br />
<%= f.text_field :rgb_color %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
But how should I do it with four zones?
You can do this with accepts_nested_attributes_for and fields_for:
Model:
class Canvas < ActiveRecord::Base
has_many :zones
accepts_nested_attributes_for :zones
end
Controller:
class CanvasesController < ApplicationController
def new
#canvas = Canvas.new
4.times { #canvas.zones.build }
end
end
View:
<%= form_for(#canvas) do |f| %>
<%= f.fields_for :zones do |zone| %>
<div class="field">
<%= zone.label :text %><br />
<%= zone.text_field :text %>
</div>
<div class="field">
<%= zone.label :rgb_color %><br />
<%= zone.text_field :rgb_color %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
For more details and explanation have a look at this:
Nested Model Form Part 1
Nested Model Form Part 2