I'm creating a database website using rails. I implemented where a user can upload an image. There are two places where you can upload an image, one for a vendor and other for the inventory. One of the model is called "photos" and the other "fotos". I'm new to rails and wasn't sure how to use the same model, "photos" to upload to the other part of the database, so I created the model "foto" and followed the tutorial. But now when you upload a photo, the button says "Create Foto". I want it to say "Create Photo". I'm not sure how to do this.
Some of my code files
_form.html.erb/fotos/view
<%= form_for([#vendor, #vendor.fotos.build]) do |f| %>
<div class="form-group1">
<%= f.label :image %>
<%= f.file_field :image, class: 'form-control1'%>
</div>
<p>
<%= f.submit %>
</p>
<% end %>
_foto.html.erb/fotos/view
<div class="media1">
<div class="media-left1">
<%= link_to image_tag(foto.image.url, class: 'media-object1'), foto.image.url, target: '_blank' %>
</div>
<div class="media-body1">
<h4 class="media-heading1"><%= foto.title %></h4>
</div>
</div>
<p>
<%= link_to 'Delete Photo', [foto.vendor, foto],
method: :delete,
data: { confirm: 'Are you sure?' } %>
</p>
show.html.erb/vendors/view
<body>
<div class = "head">
<h1>Vendor Information</h1>
<div class = "image1" >
<img src= "http://dx.deucex.com/i/logo.png" >
</div>
</div>
</body>
<%= render #vendor.fotos %>
<h3>Add a photo:</h3>
<%= render 'fotos/form' %>
<p>
<strong>Company:</strong>
<%= #vendor.company %>
</p>
<p>
<strong>Contact Name:</strong>
<%= #vendor.contact_name %>
</p>
<p>
<strong>Phone:</strong>
<%= #vendor.phone %>
</p>
<p>
<strong>Email:</strong>
<%= #vendor.email %>
</p>
<p>
<strong>MOQ:</strong>
<%= #vendor.moq %>
</p>
<p>
<strong>Cost/Item:</strong>
<%= #vendor.cost_per_item %>
</p>
<p>
<strong>Payment Method:</strong>
<%= #vendor.payment_method %>
</p>
<p>
<strong>Terms:</strong>
<%= #vendor.terms %>
</p>
<p>
<strong>Turnover Period:</strong>
<%= #vendor.turnover %>
</p>
<p>
<strong>Returns:</strong>
<%= #vendor.returns %>
</p>
<p>
<strong>Notes:</strong>
<%= #vendor.notes %>
</p>
<%= link_to 'Back', vendors_path %>
fotos_controller.rb
class FotosController < ApplicationController
def index
#fotos = Foto.order('created_at')
end
def new
#foto = Foto.new
end
def create
#vendor = Vendor.find(params[:vendor_id])
#foto = #vendor.fotos.create(photo_params)
redirect_to vendor_path(#vendor)
end
def destroy
#vendor = Vendor.find(params[:vendor_id])
#foto = #vendor.fotos.find(params[:id])
#foto.destroy
redirect_to vendor_path(#vendor)
end
private
def photo_params
params.require(:foto).permit(:title, :image)
end
end
foto.rb/model
class Foto < ApplicationRecord
has_attached_file :image
belongs_to :vendor
validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/
end
migration file
class CreateFotos < ActiveRecord::Migration[5.1]
def change
create_table :fotos do |t|
t.string :title
t.references :vendor, foreign_key: true
t.timestamps
end
end
end
another migration file
class AddAttachmentImageToFotos < ActiveRecord::Migration[5.1]
def self.up
change_table :fotos do |t|
t.attachment :image
end
end
def self.down
remove_attachment :fotos, :image
end
end
<%= f.submit 'Create Photo' %>
This should rename the button. For more options use the following link
https://apidock.com/rails/ActionView/Helpers/FormBuilder/submit
There are two ways.
1. Pass a value to submit_tag
<%= f.submit 'Create Photo' %>
2. Use the I18N module
# config/locales/en.yml
en:
helpers:
submit:
foto:
create: "Create Photo"
This approach is better if you at some point intend to translate the application. It also makes it easy to use the same form for create and update and have the correct text for each.
Related
How can I delete a record in DB at the same time when I destroy an image?
A record still remain in DB after submitting with tick <%= p.check_box :_destroy %> in _article_form.html.erb although the image is deleted.
Updated
What I did was as followings;
1. I uploaded 3 files. p.object.id are 1, 2 and 3, for example. It worked.
2. I ticked 1 file (p.object.id is 1) for destroy and submitted. It worked. Both the record in DB and the image were deleted. The rest of images (2 files) are displayed.
3. I ticked 1 file (p.object.id is 2) for destroy and submitted. It doesn't work. The record in DB and the image (p.object.id is 2) was deleted, but new record (p.object.id is 4) was inserted in DB for some reason...
\uploaders\image_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base
.
.
include CarrierWave::RMagick
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
.
.
\models\article.rb
class Article < ActiveRecord::Base
.
.
has_many :photos, dependent: :destroy
accepts_nested_attributes_for :photos, reject_if: :all_blank, allow_destroy: true
validates :content, presence: true, length: { maximum: 140 }
validate :check_for_at_least_image
.
.
def build_images
(3 - self.photos.size).times {self.photos.build}
end
def check_for_at_least_image
errors.add(:image, "select at least one") if self.photos.size <= 0
end
end
\models\photo.rb
class Photo < ActiveRecord::Base
belongs_to :article
mount_uploader :image, ImageUploader
end
\controller\articles_controller.rb
class ArticlesController < ApplicationController
.
.
def edit
#article = Article.find(params[:id])
#article.build_images
end
def update
#article = Article.find(params[:id])
if #article.update(article_params)
redirect_to current_user
else
render 'edit'
end
end
def destroy #This is used for destroying #article, NOT photo
#article.destroy
redirect_to root_url
end
private
def article_params
params.require(:article).permit(:content, :category_id, photos_attributes: [:id, :article_id, :image, :image_cache, :_destroy])
end
.
.
end
\view\shared\ _article_form.html.erb
<%= form_for(#article) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.fields_for :photos do |p| %>
<%= p.hidden_field :article_id %>
<div class="photo">
<% if p.object.image and p.object.image.file %>
<%= image_tag p.object.image.thumb.url %>
<%= p.hidden_field :image_cache if p.object.image_cache %>
<label><%= p.check_box :_destroy %>delete</label> #tick this check box
<% end %>
<%= p.file_field :image %>
</div>
<% end %>
<%= f.text_area :content, placeholder: "enter..." %>
</div>
<%= f.submit class: "btn btn-large btn-primary" %>
<% end %>
if you want to remove the the data from both db and view ,then i recommend this way...without using accept_nested_attributes_for which will work only after saving the parent object and will delete the child using _destroy attribute being set as true/1.
1. give your elements a unique id by passing object.id
2. use this object.id to select the element and remove it using js.erb with a remote call/ajax on same page on success
==========first method(without accept_nested_attributes-for)======================
---------using remote method call(without setting _destroy)----------------
<%= form_for(#article) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.fields_for :photos do |p| %>
<%= p.hidden_field :article_id %>
##here i added id field which i need to recognize using id
<div class="photo" id="photo_<%= p.id %>">
<% if p.object.image and p.object.image.file %>
<%= image_tag p.object.image.thumb.url %>
<%= p.hidden_field :image_cache if p.object.image_cache %>
##instead of checkbox,use link_to
##<label><%= p.check_box :_destroy %>delete</label> #tick this check box
<%= link_to "Delete", article_path(p),{:method => :delete,:remote=>true%>
</td>
<% end %>
<%= p.file_field :image %>
</div>
<% end %>
<%= f.text_area :content, placeholder: "enter..." %>
</div>
<%= f.submit class: "btn btn-large btn-primary" %>
<% end %>
in articles_controller.rb
def destroy
##first remove from db and then from view using id passed
#article=Artice.find params[:id]
#audio.destroy
respond_to do |format|
format.js
end
end
in destroy.js.erb
##delete the image from your view using p.id with a slideup animation(if needed)
$("#photo_<%= params[:id] %").slideUp("slow", function() { $('#photo_<%= params[:id]%>').remove();});
==========second method(using accept nested attribute for)==========================
---------using jquery to delete image and marking object to destruction by setting _destroy to 1(using _destroy by setting it to 1)-------
in your view
<%= form_for(#article) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.fields_for :photos do |p| %>
<%= p.hidden_field :article_id %>
<div class="photo">
<% if p.object.image and p.object.image.file %>
<%= image_tag p.object.image.thumb.url %>
<%= p.hidden_field :image_cache if p.object.image_cache %>
##on click of checkbox,set _destroy to 1,which will get deleted by parent
##when parent is updated/saved
<label><%= p.check_box :_destroy :class => 'delete_member', :p_id => p.id %>
delete</label> #tick this check box
</td>
<% end %>
<%= p.file_field :image %>
</div>
<% end %>
<%= f.text_area :content, placeholder: "enter..." %>
</div>
<%= f.submit class: "btn btn-large btn-primary" %>
<% end %>
your jquery
$('.delete_member').click(function(){
//remove div from screen using class photo
$(this).closest('.photo').remove();
//get relevant id to remove/mark as delete
id =jQuery(this).attr('p_id');
//remove/mark the nested model/record as ready for deletion for rails by adding true/1 value
$("input[p_id="+id+"]").attr('value',1);
So after setting _destroy to 1,the record will also gets removed by rails as we have marked it for destruction using _destroy attribute
dependent: :destroy should work if you destroy an article it should destroy the photos. If that's buggy, you can always create a callback "before_destroy" or "after_destroy".
you could try rename _destroy to remove_file or remove_<mounted-point>
if you want to remove the file manually, you can call remove_<mounted-point>!, then save the object (or do it in callback).
photo.remove_<mounted-point>!
photo.save
I have two models: PointPage and PointPageClass, which belongs_to :point_page. When user create PointPage rails creates several (now there're 6 of them) PointPageClasses in database. I need to edit all of them on PointPage edit page. So, I'm using nested attributes in controller and fields_for in view.
point_page_form
<%= form_for #point_page, role: 'form' do |f| %>
<div class="form-group">
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
</div>
... # some other PointPage fields
<% #point_page.point_page_classes.each do |class| %>
<%= f.fields_for :point_page_classes do |builder| %>
<div class="row">
<div class="col-lg-6">
<%= builder.text_field :distance_price, class: 'form-control' %>
</div>
<div class="col-lg-6">
<%= builder.text_field :show_price, class: 'form-control' %>
</div>
</div>
<% end %>
<% end %>
<%= f.submit 'Save', class: 'btn btn-default' %>
<% end %>
point_page_controller
def update
#point_page = PointPage.find(params[:id])
if #point_page.update_attributes(point_page_params)
respond_to do |format|
format.html { redirect_to new_point_path }
format.js
end
end
end
private
def point_page_params
params.require(:point_page).permit(:name, :url, :article,
point_page_classes_attributes: [:distance_price, :show_price])
end
So, I've added in point_page_controller PointPageClass attributes, but when I save the changes, it only saves changes for PointPage, but not for PointPageClass (distance_price and show_price).
Thanks for any help!
One of the problem could be not permitting the :id in the point_page_params.For the update to take place you need to permit the :id.
Try changing your point_page_params to like this
def point_page_params
params.require(:point_page).permit(:id,:name, :url, :article,point_page_classes_attributes: [:id,:distance_price, :show_price])
end
I'm new to Rails and struggling to get my belongs_to association right. I have an app where a painting belongs to an artist and an artist can have_many paintings. I can create and edit my paintings, however I can not edit or create artists except through the console. Through much Googling I feel I have got myself turned around. Any help would be much appreciated!
Here's my routes.rb file:
MuseumApp::Application.routes.draw do
resources :paintings
resources :paintings do
resources :artists
resources :museums
end
root 'paintings#index'
end
Here's my paintings Controller
def show
#painting = Painting.find params[:id]
end
def new
#painting = Painting.new
##artist = Artist.new
end
def create
safe_painting_params = params.require(:painting).permit(:title, :image)
#painting = Painting.new safe_painting_params
if #painting.save
redirect_to #painting
else
render :new
end
end
def destroy
#painting = Painting.find(params[:id])
#painting.destroy
redirect_to action: :index
end
def edit
#painting = Painting.find(params[:id])
end
def update
#painting = Painting.find(params[:id])
if #painting.update_attributes(params[:painting].permit(:title, :image)) #safe_params
redirect_to #painting
else
render :edit
end
end
Here's the form in my paintings view:
<%= form_for(#painting) do |f| %>
<fieldset>
<legend>painting</legend>
<div>
<%= f.label :title %>
<%= f.text_field :title %>
</div>
<div>
<%= f.label :image %>
<%= f.text_field :image %>
</div>
<%= form_for([#painting,#painting.create_artist]) do |f| %>
<div>
<%= f.label :Artist %>
<%= f.text_field :name %>
</div>
</fieldset>
<%= f.submit %>
<% end %>
<% end %>
Artists Controller:
class ArtistsController < ApplicationController
def index
#artists = Artist.all
#artists = params[:q] ? Artist.search_for(params[:q]) : Artist.all
end
def show
#artist = Artist.find params[:id]
end
def new
#artist = Artist.new
end
def create
#painting = Painting.find(params[:painting_id])
#artist = #painting.create_artist(artist_params)
redirect_to painting_path(#painting)
end
def destroy
#artist = Artist.find(params[:id])
#Artist.destroy
redirect_to action: :index
end
def edit
#artist = Artist.find(params[:id])
end
def update
#painting = Painting.find(params[:painting_id])
#artist = #artist.update_attributes(artist_params)
redirect_to painting_path(#painting)
end
end
private
def artist_params
params.require(:artist).permit(:name)
end
Index view:
<h1> Hello and Welcome to Museum App</h1>
<h3><%= link_to "+ Add To Your Collection", new_painting_artist_path %></h3>
<%= form_tag '/', method: :get do %>
<%= search_field_tag :q, params[:q] %>
<%= submit_tag "Search" %>
<% end %>
<br>
<div id="paintings">
<ul>
<% #paintings.each do |painting| %>
<li><%= link_to painting.title, {action: :show, id:painting.id} %> by <%= painting.artist_name %></li>
<div id = "img">
<br><%= link_to (image_tag painting.image), painting.image %><br>
</div>
<%= link_to "Edit", edit_painting_path(id: painting.id) %>
||
<%= link_to 'Destroy', {action: :destroy, id: painting.id},method: :delete, data: {confirm: 'Are you sure?'} %>
<% end %>
</ul>
</div>
In your case you should use accepts_nested_attributes_for and fields_for to achieve this.
Artist
has_many :paintings, :dependent => :destroy
accepts_nested_attributes_for :paintings
Painting
belongs_to :artist
And also you should try creating artist with paintings like this
form_for(#artist) do |f| %>
<fieldset>
<legend>Artist</legend>
<%= f.label :Artist %>
<%= f.text_field :name %>
<%= fields_for :paintings, #artist.paintings do |artist_paintings| %>
<%= artist_paintings.label :title %>
<%= artist_paintings.text_field :title %>
<%= artist_paintings.label :image %>
<%= artsist_paintings.text_field :image %>
</fieldset>
<%= f.submit %>
<% end %>
Note:
You should be having your Artist Controller with at least new,create,edit and update methods defined in it to achieve this.
Edit
Try the reverse
Artist
has_many :paintings, :dependent => :destroy
Painting
belongs_to :artist
accepts_nested_attributes_for :paintings
form_for(#painting) do |f| %>
<fieldset>
<legend>Painting</legend>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.label :image %>
<%= f.text_field :image %>
<%= fields_for :artists, #painting.artists do |ff| %>
<%= ff.label :Artist %>
<%= ff.text_field :name %>
</fieldset>
<%= f.submit %>
<% end %>
Put this form in paintings views.
I have a Rails 4 application and just installed the Paperclip gem to handle image uploading. I can't get it working, after I've uploaded a photo it just says missing.
Someone has a clue what's going wrong?
~settings/_form.html.erb
> <%= form_for(#setting, :html => { :multipart => true }) do |f| %>
> <% if #setting.errors.any? %>
> <div id="error_explanation">
> <h2><%= pluralize(#setting.errors.count, "error") %> prohibited this setting from being saved:</h2>
>
> <ul>
> <% #setting.errors.full_messages.each do |msg| %>
> <li><%= msg %></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 :paragraph %><br>
> <%= f.text_area :paragraph %>
> </div>
> <div>
> <%= f.file_field :photo %>
> </div>
> <div class="actions">
> <%= f.submit %>
> </div>
> <% end %>
My setting model ~setting.rb
class Setting < ActiveRecord::Base
attr_accessible :title, :description, :paragraph
has_attached_file :photo
end
Photo Migration
class AddAttachmentPhotoToSettings < ActiveRecord::Migration
def self.up
change_table :settings do |t|
t.attachment :photo
end
end
def self.down
drop_attached_file :settings, :photo
end
end
Setting migration
class CreateSettings < ActiveRecord::Migration
def change
create_table :settings do |t|
t.string :title
t.text :description
t.text :paragraph
t.timestamps
end
end
end
~settings/Show.html.erb
<p id="notice"><%= notice %></p>
<p> <%= image_tag #setting.photo.url %> </p> <br />
<p>
<strong>Title:</strong>
<%= #setting.title %>
</p>
<p>
<strong>Description:</strong>
<%= #setting.description %>
</p>
<p>
<strong>Paragraph:</strong>
<%= #setting.paragraph %>
</p>
<%= link_to 'Edit', edit_setting_path(#setting) %> |
<%= link_to 'Back', settings_path %>
Can't figure out what's wrong. The uploaded photo does'nt show it just says "Missing". Would appreciate some help! :)
You can keep the first one : setting_params. It seems to be a method in your controller to ensure strong parameters (see: http://guides.rubyonrails.org/getting_started.html#saving-data-in-the-controller).
To resolve it, add the relation in this method like this :
private
def setting_params
params.require(:post).permit(:title, :description, :paragraph, :photo)
end
I'm glad to tell everyone that have or will have the same problem that I just figured it out!
By default your generated controller that you want to add the :photo attribute to defines "create" like this:
def create
#setting = Setting.new(setting_params)
end
Just cange it to:
def create
#setting = Setting.create(params[:setting])
end
(Just to be clear; Change setting to your own scaffold name.)
How can I make this work in Rails 2.3?
class Magazine < ActiveRecord::Base
has_many :magazinepages
end
class Magazinepage < ActiveRecord::Base
belongs_to :magazine
end
and then in the controller:
def new
#magazine = Magazine.new
#magazinepages = #magazine.magazinepages.build
end
and then the form:
<% form_for(#magazine) do |f| %>
<%= error_messages_for :magazine %>
<%= error_messages_for :magazinepages %>
<fieldset>
<legend><%= t('new_magazine') %></legend>
<p>
<%= f.label :title %>
<%= f.text_field :title %>
</p>
<fieldset>
<legend><%= t('new_magazine_pages') %>
<% f.fields_for :magazinepages do |p| %>
<p>
<%= p.label :name %>
<%= p.text_field :name %>
</p>
<p>
<%= p.file_field :filepath %>
</p>
<% end %>
</fieldset>
<p>
<%= f.submit :save %>
</p>
</fieldset>
<% end %>
problem is, if I want to submit a collection of magazinepages, activerecord complaints because it's expected a model and not an array.
create action:
def create
#magazine = Magazine.new params[:magazine]
#magazine.save ? redirect_to(#magazine) : render(:action => 'new')
end
In magazine:
accepts_nested_attributes_for :magazinepages
Magazine.new(params[:magazine]) will then handle the object hierarchy for you automatically
I'm not 100% sure what you're asking, but if you're trying to instantiate a new magazine, with many magazinepages, you'll need to iterate over each magazine page. Something like this:
def create
#magazine = Magazine.new(params[:magazine])
if params[:magazinepages]
params[:magazinepages].each do |page|
#magazine.magazinepages.build(page)
end
end
# Save the model, do your redirection or rendering invalid model etc
end