CarrierWave, Paperclip, और Dragonfly जैसे कई फ़ाइल अपलोडिंग जेम हैं, बस कुछ नाम लेने के लिए। उन सभी की अपनी विशिष्टताएं हैं, और शायद आपने पहले से ही इनमें से कम से कम एक जेम का उपयोग किया है।
हालांकि, आज मैं एक अपेक्षाकृत नए, लेकिन बहुत अच्छे समाधान का परिचय देना चाहता हूं जिसे Shrine कहा जाता है, जिसे Janko Marohnić द्वारा बनाया गया है। कुछ अन्य समान जेम के विपरीत, इसका एक मॉड्यूलर दृष्टिकोण है, जिसका अर्थ है कि हर सुविधा एक मॉड्यूल (या Shrine की शब्दावली में प्लगइन) के रूप में पैक की गई है। वैलिडेशन का समर्थन चाहते हैं? एक प्लगइन जोड़ें। कुछ फ़ाइल प्रोसेसिंग करना चाहते हैं? एक प्लगइन जोड़ें! मैं वास्तव में इस दृष्टिकोण से प्यार करता हूं क्योंकि यह आपको आसानी से नियंत्रित करने की अनुमति देता है कि कौन सी सुविधाएं किस मॉडल के लिए उपलब्ध होंगी।
इस लेख में मैं आपको दिखाने जा रहा हूं कि कैसे:
- Shrine को Rails एप्लिकेशन में एकीकृत करें
- इसे कॉन्फ़िगर करें (वैश्विक और प्रति-अपलोडर)
- फ़ाइलें अपलोड करने की क्षमता जोड़ें
- फ़ाइलों को प्रोसेस करें
- वैलिडेशन नियम जोड़ें
- अतिरिक्त मेटाडेटा संग्रहीत करें और Amazon S3 के साथ फ़ाइल क्लाउड स्टोरेज का उपयोग करें
इस लेख का स्रोत कोड GitHub पर उपलब्ध है।
कार्यशील डेमो यहां पाया जा सकता है।
Shrine को एकीकृत करना
शुरू करने के लिए, डिफ़ॉल्ट टेस्टिंग सूट के बिना एक नया Rails एप्लिकेशन बनाएं:
rails new FileGuru -T
मैं इस डेमो के लिए Rails 5 का उपयोग करूंगा, लेकिन अधिकांश अवधारणाएं संस्करण 3 और 4 पर भी लागू होती हैं।
Shrine जेम को अपने Gemfile में डालें:
gem "shrine"
फिर चलाएं:
bundle install
अब हमें एक मॉडल की आवश्यकता होगी जिसे मैं Photo कहूंगा। Shrine सभी फ़ाइल-संबंधी जानकारी को एक विशेष टेक्स्ट कॉलम में संग्रहीत करता है जो _data सफ़िक्स के साथ समाप्त होता है। संबंधित माइग्रेशन बनाएं और लागू करें:
rails g model Photo title:string image_data:text rails db:migrate
ध्यान दें कि Rails के पुराने संस्करणों के लिए, बाद की कमांड होनी चाहिए:
rake db:migrate
Shrine के लिए कॉन्फ़िगरेशन विकल्प वैश्विक और प्रति-मॉडल दोनों पर सेट किए जा सकते हैं। वैश्विक सेटिंग्स, निश्चित रूप से, इनिशियलाइज़र फ़ाइल के अंदर की जाती हैं। वहां मैं आवश्यक फ़ाइलों और प्लगइन्स को हुक करने जा रहा हूं। प्लगइन्स का उपयोग Shrine में कार्यक्षमता के टुकड़ों को अलग-अलग मॉड्यूल में निकालने के लिए किया जाता है, जिससे आपको सभी उपलब्ध सुविधाओं पर पूर्ण नियंत्रण मिलता है। उदाहरण के लिए, वैलिडेशन, छवि प्रसंस्करण, अटैचमेंट कैशिंग, और बहुत कुछ के लिए प्लगइन्स हैं।
अभी के लिए, आइए दो प्लगइन्स जोड़ें: एक ActiveRecord का समर्थन करने के लिए और दूसरा लॉगिंग सेट अप करने के लिए। उन्हें वैश्विक रूप से शामिल किया जाएगा। साथ ही, फ़ाइल सिस्टम स्टोरेज सेट अप करें:
config/initializers/shrine.rb
require "shrine"
require "shrine/storage/file_system"
Shrine.plugin :activerecord
Shrine.plugin :logging, logger: Rails.logger
Shrine.storages = {
cache: Shrine::Storage::FileSystem.new("public", prefix: "uploads/cache"),
store: Shrine::Storage::FileSystem.new("public", prefix: "uploads/store"),
}
लॉगर बस आपके लिए कंसोल के अंदर कुछ डीबगिंग जानकारी आउटपुट करेगा जिसमें कहा जाएगा कि फ़ाइल को प्रोसेस करने में कितना समय लगा। यह काम आ सकता है।
2015-10-09T20:06:06.676Z #25602: STORE[cache] ImageUploader[:avatar] User[29543] 1 file (0.1s) 2015-10-09T20:06:06.854Z #25602: PROCESS[store]: ImageUploader[:avatar] User[29543] 1-3 files (0.22s) 2015-10-09T20:06:07.133Z #25602: DELETE[destroyed]: ImageUploader[:avatar] User[29543] 3 files (0.07s)
सभी अपलोड की गई फ़ाइलें public/uploads निर्देशिका के अंदर संग्रहीत की जाएंगी। मैं इन फ़ाइलों को Git में ट्रैक नहीं करना चाहता, इसलिए इस फ़ोल्डर को बाहर रखें:
.gitignore
public/uploads
अब एक विशेष "अपलोडर" क्लास बनाएं जो मॉडल-विशिष्ट सेटिंग्स को होस्ट करने जा रहा है। अभी के लिए, यह क्लास खाली होने जा रही है:
models/image_uploader.rb
class ImageUploader < Shrine end
अंत में, इस क्लास को Photo मॉडल के अंदर शामिल करें:
models/photo.rb
include ImageUploader[:image]
[:image] एक वर्चुअल विशेषता जोड़ता है जिसका उपयोग फ़ॉर्म बनाते समय किया जाएगा। उपरोक्त लाइन को इस तरह भी लिखा जा सकता है:
include ImageUploader.attachment(:image) # or include ImageUploader::Attachment.new(:image)
बहुत बढ़िया! अब मॉडल Shrine की कार्यक्षमता से लैस है, और हम अगले चरण पर आगे बढ़ सकते हैं।
कंट्रोलर, व्यू, और रूट्स
इस डेमो के उद्देश्यों के लिए, हमें फ़ोटो प्रबंधित करने के लिए केवल एक कंट्रोलर की आवश्यकता होगी। index पेज रूट के रूप में काम करेगा:
pages_controller.rb
class PhotosController < ApplicationController
def index
@photos = Photo.all
end
end
व्यू:
views/photos/index.html.erb
<h1>Photos</h1> <%= link_to 'Add Photo', new_photo_path %> <%= render @photos %>
@photos सरणी को रेंडर करने के लिए, एक पार्शियल की आवश्यकता होती है:
views/photos/_photo.html.erb
<div>
<% if photo.image_data? %>
<%= image_tag photo.image_url %>
<% end %>
<p><%= photo.title %> | <%= link_to 'Edit', edit_photo_path(photo) %></p>
</div>
image_data? ActiveRecord द्वारा प्रस्तुत एक विधि है जो जांचती है कि क्या किसी रिकॉर्ड में छवि है।
image_url एक Shrine विधि है जो बस मूल छवि का पथ वापस करती है। बेशक, एक छोटा थंबनेल प्रदर्शित करना बेहतर है, लेकिन हम इसका बाद में ध्यान रखेंगे।
सभी आवश्यक रूट्स जोड़ें:
config/routes.rb
resources :photos, only: [:new, :create, :index, :edit, :update] root 'photos#index'
यही है—जमीनी काम हो गया है, और हम दिलचस्प हिस्से पर आगे बढ़ सकते हैं!
फ़ाइलें अपलोड करना
इस अनुभाग में मैं आपको दिखाऊंगा कि वास्तव में फ़ाइलें अपलोड करने की कार्यक्षमता कैसे जोड़ें। कंट्रोलर एक्शन बहुत सरल हैं:
photos_controller.rb
def new
@photo = Photo.new
end
def create
@photo = Photo.new(photo_params)
if @photo.save
flash[:success] = 'Photo added!'
redirect_to photos_path
else
render 'new'
end
end
एकमात्र पकड़ यह है कि स्ट्रॉन्ग पैरामीटर्स के लिए आपको image_data नहीं, बल्कि image वर्चुअल विशेषता की अनुमति देनी होगी।
photos_controller.rb
private def photo_params params.require(:photo).permit(:title, :image) end
new व्यू बनाएं:
views/photos/new.html.erb
<h1>Add photo</h1> <%= render 'form' %>
फ़ॉर्म का पार्शियल भी तुच्छ है:
views/photos/_form.html.erb
<%= form_for @photo do |f| %> <%= render "shared/errors", object: @photo %> <%= f.label :title %> <%= f.text_field :title %> <%= f.label :image %> <%= f.file_field :image %> <%= f.submit %> <% end %>
एक बार फिर, ध्यान दें कि हम image_data नहीं, बल्कि image विशेषता का उपयोग कर रहे हैं।
अंत में, एरर प्रदर्शित करने के लिए एक और पार्शियल जोड़ें:
views/shared/_errors.html.erb
<% if object.errors.any? %>
<h3>The following errors were found:</h3>
<ul>
<% object.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
<% end %>
यह बहुत अधिक है—आप अभी छवियां अपलोड करना शुरू कर सकते हैं।
वैलिडेशन
बेशक, डेमो ऐप को पूरा करने के लिए बहुत अधिक काम करना होगा। मुख्य समस्या यह है कि उपयोगकर्ता किसी भी प्रकार की फ़ाइल को किसी भी आकार के साथ अपलोड कर सकते हैं, जो विशेष रूप से अच्छा नहीं है। इसलिए, वैलिडेशन का समर्थन करने के लिए एक और प्लगइन जोड़ें:
config/initializers/shrine.rb
Shrine.plugin :validation_helpers
ImageUploader के लिए वैलिडेशन तर्क सेट अप करें:
models/image_uploader.rb
Attacher.validate do validate_max_size 1.megabyte, message: "is too large (max is 1 MB)" validate_mime_type_inclusion ['image/jpg', 'image/jpeg', 'image/png'] end
मैं केवल 1MB से कम JPG और PNG छवियों को अपलोड करने की अनुमति दे रहा हूं। इन नियमों को जैसा आप फिट देखें वैसा tweak करें।
MIME प्रकार
ध्यान देने योग्य एक और महत्वपूर्ण बात यह है कि, डिफ़ॉल्ट रूप से, Shrine Content-Type HTTP हेडर का उपयोग करके फ़ाइल के MIME प्रकार का निर्धारण करेगा। यह हेडर ब्राउज़र द्वारा पास किया जाता है और केवल फ़ाइल के एक्सटेंशन के आधार पर सेट किया जाता है, जो हमेशा वांछनीय नहीं होता है।
यदि आप फ़ाइल की सामग्री के आधार पर MIME प्रकार निर्धारित करना चाहते हैं, तो determine_mime_type नामक एक प्लगइन का उपयोग करें। मैं इसे अपलोडर क्लास के अंदर शामिल करूंगा, क्योंकि अन्य मॉडलों को इस कार्यक्षमता की आवश्यकता नहीं हो सकती है:
models/image_uploader.rb
plugin :determine_mime_type
यह प्लगइन डिफ़ॉल्ट रूप से Linux की फ़ाइल उपयोगिता का उपयोग करने जा रहा है।
अटैच की गई छवियों को कैश करना
वर्तमान में, जब कोई उपयोगकर्ता गलत डेटा के साथ एक फ़ॉर्म सबमिट करता है, तो फ़ॉर्म ऊपर रेंडर की गई एरर के साथ फिर से प्रदर्शित होगा। हालांकि, समस्या यह है कि अटैच की गई छवि खो जाएगी, और उपयोगकर्ता को इसे फिर से चुनना होगा। इसे एक और प्लगइन का उपयोग करके ठीक करना बहुत आसान है जिसे cached_attachment_data कहा जाता है:
models/image_uploader.rb
plugin :cached_attachment_data
अब बस अपने फ़ॉर्म में एक हिडन फ़ील्ड जोड़ें।
views/photos/_form.html.erb
<%= f.hidden_field :image, value: @photo.cached_image_data %> <%= f.label :image %> <%= f.file_field :image %>
फ़ोटो संपादित करना
अब छवियां अपलोड की जा सकती हैं, लेकिन उन्हें संपादित करने का कोई तरीका नहीं है, तो आइए इसे तुरंत ठीक करें। संबंधित कंट्रोलर के एक्शन कुछ हद तक तुच्छ हैं:
photos_controller.rb
def edit
@photo = Photo.find(params[:id])
end
def update
@photo = Photo.find(params[:id])
if @photo.update_attributes(photo_params)
flash[:success] = 'Photo edited!'
redirect_to photos_path
else
render 'edit'
end
end
वही _form पार्शियल उपयोग किया जाएगा:
views/photos/edit.html.erb
<h1>Edit Photo</h1> <%= render 'form' %>
अच्छा, लेकिन पर्याप्त नहीं: उपयोगकर्ता अभी भी अपलोड की गई छवि को नहीं हटा सकते। इसकी अनुमति देने के लिए, हमें - अनुमान लगाएं - एक और प्लगइन की आवश्यकता होगी:
models/image_uploader.rb
plugin :remove_attachment
यह :remove_image नामक एक वर्चुअल विशेषता का उपयोग करता है, इसलिए इसे कंट्रोलर के अंदर अनुमति दें:
photos_controller.rb
def photo_params params.require(:photo).permit(:title, :image, :remove_image) end
अब बस एक चेकबॉक्स प्रदर्शित करें ताकि यदि किसी रिकॉर्ड में अटैचमेंट हो तो छवि को हटाया जा सके:
views/photos/_form.html.erb
<% if @photo.image_data? %> Remove attachment: <%= f.check_box :remove_image %> <% end %>
थंबनेल छवि उत्पन्न करना
वर्तमान में हम मूल छवियों को प्रदर्शित करते हैं, जो पूर्वावलोकन के लिए सबसे अच्छा दृष्टिकोण नहीं है: फ़ोटो बड़ी हो सकती हैं और बहुत अधिक जगह घेर सकती हैं। बेशक, आप बस CSS width और height विशेषताओं का उपयोग कर सकते हैं, लेकिन यह भी एक बुरा विचार है। आप देखते हैं, भले ही छवि को स्टाइल का उपयोग करके छोटा सेट किया गया हो, उपयोगकर्ता को अभी भी मूल फ़ाइल डाउनलोड करने की आवश्यकता होगी, जो काफी बड़ी हो सकती है।
इसलिए, प्रारंभिक अपलोड के दौरान सर्वर-साइड पर एक छोटी पूर्वावलोकन छवि उत्पन्न करना बेहतर है। इसमें दो प्लगइन्स और दो अतिरिक्त जेम शामिल हैं। सबसे पहले, जेम डालें:
gem "image_processing" gem "mini_magick", ">= 4.3.5"
Image_processing Shrine के लेखक द्वारा बनाया गया एक विशेष जेम है। यह छवियों में हेरफेर करने के लिए कुछ उच्च-स्तरीय हेल्पर विधियां प्रस्तुत करता है। यह जेम, बदले में, mini_magick पर निर्भर करता है, जो ImageMagick के लिए एक Ruby रैपर है। जैसा कि आपने अनुमान लगाया, आपको इस डेमो को चलाने के लिए अपने सिस्टम पर ImageMagick की आवश्यकता होगी।
इन नए जेम को इंस्टॉल करें:
bundle install
अब उनके निर्भरताओं के साथ प्लगइन्स शामिल करें:
models/image_uploader.rb
require "image_processing/mini_magick" class ImageUploader < Shrine include ImageProcessing::MiniMagick plugin :processing plugin :versions # other code... end
प्रोसेसिंग वह प्लगइन है जो हमें छवि में हेरफेर करने की अनुमति देता है (उदाहरण के लिए, इसे छोटा करें, घुमाएं, किसी अन्य प्रारूप में कनवर्ट करें, आदि)। वर्जन्स, बदले में, हमें छवि को विभिन्न रूपों में रखने की अनुमति देता है। इस डेमो के लिए, दो संस्करण संग्रहीत किए जाएंगे: "original" और "thumb" (300x300 पर रीसाइज़ किया गया)।
यहां एक छवि को प्रोसेस करने और इसके दो संस्करणों को संग्रहीत करने का कोड है:
models/image_uploader.rb
class ImageUploader < Shrine
process(:store) do |io, context|
{
original: io,
thumb: resize_to_limit!(io.download, 300, 300)
}
end
end
resize_to_limit! image_processing जेम द्वारा प्रदान की गई एक विधि है। यह बस एक छवि को 300x300 तक छोटा कर देता है यदि यह बड़ी है और यदि यह छोटी है तो कुछ नहीं करता है। इसके अलावा, यह मूल पहलू अनुपात को बनाए रखता है।
अब छवि प्रदर्शित करते समय, आपको बस image_url विधि को :original या :thumb तर्क प्रदान करने की आवश्यकता है:
views/photos/_photo.html.erb
<div>
<% if photo.image_data? %>
<%= image_tag photo.image_url(:thumb) %>
<% end %>
<p><%= photo.title %> | <%= link_to 'Edit', edit_photo_path(photo) %></p>
</div>
यही चीज़ फ़ॉर्म के अंदर भी की जा सकती है:
views/photos/_form.html.erb
<% if @photo.image_data? %> <%= image_tag @photo.image_url(:thumb) %> Remove attachment: <%= f.check_box :remove_image %> <% end %>
अपलोड पूरा होने के बाद प्रोसेस की गई फ़ाइलों को स्वचालित रूप से हटाने के लिए, आप delete_raw नामक एक प्लगइन जोड़ सकते हैं:
models/image_uploader.rb
plugin :delete_raw
छवि का मेटाडेटा
छवि को वास्तव में रेंडर करने के अलावा, आप उसका मेटाडेटा भी प्राप्त कर सकते हैं। आइए, उदाहरण के लिए, मूल फ़ोटो का आकार और MIME प्रकार प्रदर्शित करें:
views/photos/_photo.html.erb
<div>
<% if photo.image_data? %>
<%= image_tag photo.image_url(:thumb) %>
<p>
Size <%= photo.image[:original].size %> bytes<br>
MIME type <%= photo.image[:original].mime_type %><br>
</p>
<% end %>
<p><%= photo.title %> | <%= link_to 'Edit', edit_photo_path(photo) %></p>
</div>
इसके आयामों के बारे में क्या? दुर्भाग्य से, वे डिफ़ॉल्ट रूप से संग्रहीत नहीं हैं, लेकिन यह store_dimensions नामक एक प्लगइन के साथ संभव है।
छवि के आयाम
store_dimensions प्लगइन fastimage जेम पर निर्भर करता है, इसलिए इसे अभी हुक करें:
gem 'fastimage'
चलाना न भूलें:
bundle install
अब बस प्लगइन शामिल करें:
models/image_uploader.rb
plugin :store_dimensions
और width और height विधियों का उपयोग करके आयाम प्रदर्शित करें:
views/photos/_photo.html.erb
<div>
<% if photo.image_data? %>
<%= image_tag photo.image_url(:thumb) %>
<p>
Size <%= photo.image[:original].size %> bytes<br>
MIME type <%= photo.image[:original].mime_type %><br>
Dimensions <%= "#{photo.image[:original].width}x#{photo.image[:original].height}" %>
</p>
<% end %>
<p><%= photo.title %> | <%= link_to 'Edit', edit_photo_path(photo) %></p>
</div>
इसके अलावा, एक dimensions विधि उपलब्ध है जो चौड़ाई और ऊंचाई वाली एक सरणी वापस करती है (उदाहरण के लिए, [500, 750])।
क्लाउड पर जाना
डेवलपर्स अक्सर अपलोड की गई फ़ाइलों को होस्ट करने के लिए क्लाउड सेवाओं को चुनते हैं, और Shrine ऐसी संभावना प्रस्तुत करता है। इस अनुभाग में, मैं आपको दिखाऊंगा कि फ़ाइलों को Amazon S3 पर कैसे अपलोड किया जाए।
पहले चरण के रूप में, Gemfile में दो और जेम शामिल करें:
gem "aws-sdk", "~> 2.1" group :development do gem 'dotenv-rails' end
aws-sdk S3 के SDK के साथ काम करने के लिए आवश्यक है, जबकि dotenv-rails का उपयोग विकास में पर्यावरण चर को प्रबंधित करने के लिए किया जाएगा।
bundle install
आगे बढ़ने से पहले, आपको API के माध्यम से S3 तक पहुंचने के लिए एक कुंजी जोड़ी प्राप्त करनी चाहिए। इसे प्राप्त करने के लिए, Amazon Web Services Console में साइन इन (या साइन अप) करें और Security Credentials > Users पर जाएं। S3 पर फ़ाइलों में हेरफेर करने की अनुमति के साथ एक उपयोगकर्ता बनाएं। यहां S3 तक पूर्ण पहुंच प्रस्तुत करने वाली सरल नीति है:
{
"Version": "2016-11-14",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "*"
}
]
}
बनाए गए उपयोगकर्ता की कुंजी जोड़ी डाउनलोड करें। वैकल्पिक रूप से, आप रूट एक्सेस कुंजियों का उपयोग कर सकते हैं, लेकिन मैं दृढ़ता से अनुशंसा करता हूं कि आप ऐसा न करें क्योंकि यह बहुत असुरक्षित है।
अगला, अपनी फ़ाइलों को होस्ट करने के लिए एक S3 बकेट बनाएं और प्रोजेक्ट की रूट में अपनी कॉन्फ़िगरेशन को होस्ट करने के लिए एक फ़ाइल जोड़ें:
.env
S3_KEY=YOUR_KEY S3_SECRET=YOUR_SECRET S3_BUCKET=YOUR_BUCKET S3_REGION=YOUR_REGION
कभी भी इस फ़ाइल को सार्वजनिक रूप से उजागर न करें, और सुनिश्चित करें कि आप इसे Git से बाहर रखते हैं:
.gitignore
.env
अब Shrine के वैश्विक कॉन्फ़िगरेशन को संशोधित करें और एक नया स्टोरेज पेश करें:
config/initializers/shrine.rb
require "shrine"
require "shrine/storage/s3"
s3_options = {
access_key_id: ENV['S3_KEY'],
secret_access_key: ENV['S3_SECRET'],
region: ENV['S3_REGION'],
bucket: ENV['S3_BUCKET'],
}
Shrine.storages = {
cache: Shrine::Storage::FileSystem.new("public", prefix: "uploads/cache"),
store: Shrine::Storage::S3.new(prefix: "store", **s3_options),
}
बस! ऐप के अन्य हिस्सों में कोई बदलाव नहीं करना है, और आप इस नए स्टोरेज को तुरंत टेस्ट कर सकते हैं। यदि आपको गलत कुंजियों से संबंधित S3 से एरर मिल रहे हैं, तो सुनिश्चित करें कि आपने कुंजी और सीक्रेट को बिना किसी ट्रेलिंग स्पेस और अदृश्य विशेष प्रतीकों के सटीक रूप से कॉपी किया है।
निष्कर्ष
हम इस लेख के अंत में आ गए हैं। उम्मीद है, अब तक आप Shrine का उपयोग करने में बहुत अधिक आत्मविश्वास महसूस करते हैं और इसे अपनी परियोजनाओं में से एक में नियोजित करने के लिए उत्सुक हैं। हमने इस जेम की कई विशेषताओं पर चर्चा की है, लेकिन और भी बहुत कुछ हैं, जैसे फ़ाइलों के साथ अतिरिक्त संदर्भ संग्रहीत करने की क्षमता और डायरेक्ट अपलोड तंत्र।
इसलिए, Shrine के दस्तावेज़ीकरण और इसकी आधिकारिक वेबसाइट को ब्राउज़ करें, जो सभी उपलब्ध प्लगइन्स का विस्तार से वर्णन करती है। यदि इस जेम के बारे में आपके अन्य प्रश्न हैं, तो उन्हें पोस्ट करने में संकोच न करें। मेरे साथ बने रहने के लिए धन्यवाद, और मैं जल्द ही आपसे मिलूंगा!