Subir imágenes con CarrierWave - moiseserg/rubyWebDev GitHub Wiki
Se actualiza el archivo de gemas, se agrega carrierwave
gem 'carrierwave'
gem 'mini_magick'
Ejecutar rails g
para ver el generador que permite subir los archivos
$ rails g
Running via Spring preloader in process 18654
Usage: rails generate GENERATOR [args] [options]
General options:
-h, [--help] # Print generator's options and usage
-p, [--pretend] # Run but do not make any changes
-f, [--force] # Overwrite files that already exist
-s, [--skip] # Skip files that already exist
-q, [--quiet] # Suppress status output
Please choose a generator below.
Rails:
assets
channel
controller
generator
helper
integration_test
jbuilder
job
mailer
migration
model
resource
scaffold
scaffold_controller
system_test
task
Coffee:
coffee:assets
Js:
js:assets
TestUnit:
test_unit:generator
test_unit:plugin
Uploader:
uploader
El generador que se usará es uploader
Ahora se genera un módulo para subir los archivos:
$ rails g uploader Image
Running via Spring preloader in process 18873
create app/uploaders/image_uploader.rb
Podrá visualizar
class ImageUploader < CarrierWave::Uploader::Base
# Include RMagick or MiniMagick support:
# include CarrierWave::RMagick
# include CarrierWave::MiniMagick
# Choose what kind of storage to use for this uploader:
storage :file
# storage :fog
# Override the directory where uploaded files will be stored.
# This is a sensible default for uploaders that are meant to be mounted:
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
# Provide a default URL as a default if there hasn't been a file uploaded:
# def default_url(*args)
# # For Rails 3.1+ asset pipeline compatibility:
# # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
#
# "/images/fallback/" + [version_name, "default.png"].compact.join('_')
# end
# Process files as they are uploaded:
# process scale: [200, 300]
#
# def scale(width, height)
# # do something
# end
# Create different versions of your uploaded files:
# version :thumb do
# process resize_to_fit: [50, 50]
# end
# Add a white list of extensions which are allowed to be uploaded.
# For images you might use something like this:
# def extension_whitelist
# %w(jpg jpeg gif png)
# end
# Override the filename of the uploaded files:
# Avoid using model.id or version_name here, see uploader/store.rb for details.
# def filename
# "something.jpg" if original_filename
# end
end
- Descomentar la línea que contiene
include CarrierWave::MiniMagick
para poder utilizar la gema mini_magic
-
storage :file
permite usar el sistema de archivos local para almacenar la información. Por otro lado,:fog
es otra gema que permite administrar archivos en la nube.
# Choose what kind of storage to use for this uploader:
storage :file
# storage :fog
- Para permitir archivos de tipo imagen, se descomenta la siguiente sección:
# Add a white list of extensions which are allowed to be uploaded.
# For images you might use something like this:
def extension_whitelist
%w(jpg jpeg gif png)
end
- Para especificar una imagen por default si no se ha subido se descomenta la siguiente sección y se cambia para que siempre sea la misma imagen.
# Provide a default URL as a default if there hasn't been a file uploaded:
def default_url(*args)
# # For Rails 3.1+ asset pipeline compatibility:
ActionController::Base.helpers.asset_path("default.png")
#
# "/images/fallback/" + [version_name, "default.png"].compact.join('_')
end
- Para generar una versión reducida de la imagen, se puede usar el siguiente fragmento:
# Create different versions of your uploaded files:
version :thumb do
process resize_to_fill: [150, 150]
end
Se generará un modelo que corresponderá a un producto, regresando al ejemplo de las pizzas:
rails g scaffold Product name:string description:text price:float quantity:integer image:string
Después de generar el modelo, se modifica en app/models/product.rb el archivo quedando:
class Product < ApplicationRecord
mount_uploader :image, ImageUploader
end
- El método
mount_uploader
permite hacer la carga de:image
(del modelo Producto) ligada con elImageUploader
Como se había definido una imagen por default para los modelos que no tengan la imagen, se copia alguna imagen con el nombre especificado a la carpeta app/assets/images.
Si se sube una imagen:
Cuando se muestre se verá la cadena asociada al campo de imagen:
Para poder visualizar la imagen (en este caso la imagen que se estableció por default
Se requiere escribir la siguiente línea:
<%= image_tag @product.image.thumb.url %>
en el archivo app/views/products/show.html.erb o en donde se desee mostrar la imagen almacenada.
<p>
<strong>Image:</strong>
<%= @product.image %>
<%= image_tag @product.image.thumb.url %>
</p>
note que realmente se debe eliminar <%= @product.image %>
ya que en general sólo se requiere la imagen no su URL.
En el archivo app/views/product/index.html.erb, la línea <% @products.each do |product| %>
hace un ciclo sobre todos los elementos del modelo Producto donde se puede accesder a cada instancia usando la variable product, por lo que para mostrar la imagen se coloca la línea <td><%= image_tag product.image.url %></td>
si se desea la imagen original, o de otra forma por ejemplo <td><%= image_tag product.image.thumb.url %></td>
si se desea usar la miniatura creada.
<tbody>
<% @products.each do |product| %>
<tr>
<td><%= product.name %></td>
<td><%= product.description %></td>
<td><%= product.price %></td>
<td><%= product.quantity %></td>
<td><%= image_tag product.image.url %></td>
<td><%= link_to 'Show', product %></td>
<td><%= link_to 'Edit', edit_product_path(product) %></td>
<td><%= link_to 'Destroy', product, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
Para agregar el componente HTML que permite seleccionar una imagen para ser subida al servidor:
En el elemento que permite definir la imagen (definida como string en el scaffold):
<div class="field">
<%= form.label :image %>
<%= form.text_field :image, id: :product_image %>
</div>
Cambiarlo a un formulario para subir archivos:
<div class="field">
<%= form.label :image %>
<%= form.file_field :image, id: :product_image %>
</div>
- Subiendo la imagen usando el file chooser
- Después de ingresar la información, se muestra (show) el registro ingresado
- Finalmente, se puede listar usando http://localhost:3000/products
Un video muy util Curso de Ruby on Rails, Subir imagenes