"রেইলসে আপলোডিং" সিরিজের এই еще একটি নিবন্ধ। আজ আমরা ক্যারিয়ারওয়েভের সাথে পরিচিত হব—রেইলসের জন্য সবচেয়ে জনপ্রিয় ফাইল আপলোড সমাধানগুলির একটি। ক্যারিয়ারওয়েভ আমার পছন্দ কারণ এটি সহজে শুরু করা যায়, আউট-অফ-দ-বক্সে অনেক ফিচার থাকে, এবং কমিউনিটি সদস্যদের লেখা দশকগুলো "কিভাবে করবেন" আর্টিকেল রয়েছে, যাতে আপনি পথ হরণ না করেন।
আপনি কী শিখবেন
- রেইলস অ্যাপে ক্যারিয়ারওয়েভ ইন্টিগ্রেট করা
- ভ্যালিডেশন যোগ করা
- অনুরোধ জুড়ে ফাইল টিকে রাখা
- ফাইল মুছে ফেলা
- থাম্বনেইল তৈরি করা
- রিমোট লোকেশন থেকে ফাইল আপলোড করা
- একাধিক ফাইল আপলোডের সমর্থন যোগ করা
- ক্লাউড স্টোরেজের জন্য সমর্থন যোগ করা
এই নিবন্ধের সোর্স কোড গিটহাবে পাওয়া যাবে। পাঠনীয়!
ভিত্তি স্থাপন
সর্বদা কিছুই, একটি নতুন রেইলস অ্যাপ্লিকেশন তৈরি দিয়ে শুরু করুন:
rails new UploadingWithCarrierwave -T
এই ডেমোতে আমি রেইলস ৫.০.২ ব্যবহার করছি। মনে রাখবেন যে ক্যারিয়ারওয়েভ ১ শুধু রেইলস ৪+ এবং রুবি ২ সমর্থন করে। যদি আপনি এখনও রেইলস ৩-এ আছেন, তবে ক্যারিয়ারওয়েভ সংস্করণ ০.১১ ব্যবহার করুন।
ক্যারিয়ারওয়েভ কাজে দেখতে, আমরা একটি খুব সাধারণ ব্লগিং অ্যাপ্লিকেশন তৈরি করব যার একমাত্র Post মডেল থাকবে। এর মূল অ্যাট্রিবিউটগুলো হবে:
title(string)body(text)image(string)—এই ফিল্ডে পোস্টের সাথে যুক্ত একটি ছবি থাকবে (বাস্তবে ফাইলের নাম)
একটি নতুন মাইগ্রেশন তৈরি ও প্রয়োগ করুন:
rails g model Post title:string body:text image:string rails db:migrate
রাউট সেট আপ করুন:
config/routes.rb
resources :posts root to: 'posts#index'
একটি বেসিক কন্ট্রোলার তৈরি করুন:
posts_controller.rb
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update]
def index
@posts = Post.order('created_at DESC')
end
def show; end
def new
@post = Post.new
end
def create
@post = Post.new(post_params)
if @post.save
redirect_to posts_path
else
render :new
end
end
def edit; end
def update
if @post.update_attributes(post_params)
redirect_to post_path(@post)
else
render :edit
end
end
private
def post_params
params.require(:post).permit(:title, :body, :image)
end
def set_post
@post = Post.find(params[:id])
end
end
এখন index ভিউ তৈরি করুন:
views/posts/index.html.erb
<h1>Posts</h1> <%= link_to 'Add post', new_post_path %> <%= render @posts %>
এবং সংশ্লিষ্ট পার্শিয়াল:
views/posts/_post.html.erb
<h2><%= link_to post.title, post_path(post) %></h2> <p><%= truncate(post.body, length: 150) %></p> <p><%= link_to 'Edit', edit_post_path(post) %></p> <hr>
এখানে রেইলস truncate মেথড ব্যবহার করা হয়েছে পোস্টের প্রথম ১৫০ ক্যারেক্টার দেখানোর জন্য। অন্যান্য ভিউ এবং ফর্ম পার্শিয়াল তৈরি করার আগে, আমরা প্রথমে ক্যারিয়ারওয়েভকে অ্যাপ্লিকেশনে ইন্টিগ্রেট করব।
ক্যারিয়ারওয়েভ ইন্টিগ্রেট করা
Gemfile-এ একটি নতুন জেম যোগ করুন:
Gemfile
gem 'carrierwave', '~> 1.0'
চালান:
bundle install
ক্যারিয়ারওয়েভ কনফিগারেশন আপলোডার-এ সংরক্ষণ করে যা আপনার মডেলে অন্তর্ভুক্ত থাকে। একটি আপলোডার তৈরি করতে নিচের কমান্ড ব্যবহার করুন:
rails generate uploader Image
এখন app/uploaders ভিতরে image_uploader.rb নামে একটি নতুন ফাইল পাবেন। এতে কিছু কার্যকর কমেন্ট ও উদাহরণ রয়েছে, তাই এটি থেকে শুরু করতে পারেন। এই ডেমোতে আমরা অ্যাক্টিভরেকর্ড ব্যবহার করব, তবে ক্যারিয়ারওয়েভ Mongoid, Sequel, এবং DataMapper-কেও সমর্থন করে।
এরপর, এই আপলোডারকে মডেলে মাউন্ট বা অন্তর্ভুক্ত করতে হবে:
models/post.rb
mount_uploader :image, ImageUploader
আপলোডারের ইতিমধ্যে ভালো ডিফল্ট সেটিংস রয়েছে, কিন্তু কমপক্ষে আপলোড হওয়া ফাইলগুলো কোথায় সংরক্ষিত হবে তা বেছে নিতে হবে। ফাইল স্টোরেজ ব্যবহার করি:
uploaders/image_uploader.rb
storage :file
ডিফল্টরূপে ফাইলগুলো public/uploads ডিরেক্টরিতে রাখা হবে, তাই ভালো হবে এই ফোল্ডারটিকে ভার্সন কন্ট্রোল থেকে বাদ দেওয়া:
.gitignore
public/uploads
আপনি আপলোডারের store_dir মেথড পরিবর্তন করে অন্য লোকেশনও বেছে নিতে পারেন।
এই পর্যায়ে, আমরা একটি নতুন ভিউ এবং ফর্ম পার্শিয়াল তৈরি করে ফাইল আপলোড শুরু করতে পারি:
views/posts/new.html.erb
<h1>Add post</h1> <%= render 'form', post: @post %>
views/posts/_form.html.erb
<%= form_for post do |f| %>
<div>
<%= f.label :title %>
<%= f.text_field :title %>
</div>
<div>
<%= f.label :body %>
<%= f.text_area :body %>
</div>
<div>
<%= f.label :image %>
<%= f.file_field :image %>
</div>
<%= f.submit %>
<% end %>
PostsController মডিফাই করার দরকার নেই কারণ আমরা ইতিমধ্যে image অ্যাট্রিবিউট অনুমতি দিয়েছি।
শেষে, এডিট ভিউ তৈরি করুন:
views/posts/edit.html.erb
<h1>Edit post</h1> <%= render 'form', post: @post %>
বस! সার্ভার চালু করে একটি ছবি সহ পোস্ট তৈরি করার চেষ্টা করুন। সমস্যা হলো ছবিটি কোথাও দেখা যাচ্ছে না, তাই পরবর্তী বিভাগে শো পেজ যোগ করব!
ছবি প্রদর্শন করা
আমাদের এখনো show ভিউ তৈরি করা বাকি। এখন যোগ করুন:
views/posts/show.html.erb
<%= link_to 'All posts', posts_path %> <h1><%= @post.title %></h1> <%= image_tag(@post.image.url, alt: 'Image') if @post.image? %> <p><%= @post.body %></p> <p><%= link_to 'Edit', edit_post_path(@post) %></p>
আপনি দেখছেন, একটি আট্যাচমেন্ট প্রদর্শন করা খুব সহজ: শুধু @post.image.url বললে ছবির URL পাবেন। ফাইলের পাথ পেতে current_path মেথড ব্যবহার করুন। ক্যারিয়ারওয়েভ image? মেথডও দেয় যাতে চেক করা যায় আট্যাচমেন্ট আছে কিনা (image মেথড কখনো nil রিটার্ন করে না, ফাইল না থাকলেও)।
এখন পোস্টে যেতে ছবি দেখতে পাবেন, কিন্তু সেটি খুব বড় হতে পারে কারণ আমরা কোথাও ডাইমেনশন সীমাবদ্ধ করিনি। অবশ্য CSS দিয়ে ছোট করা যেত, কিন্তু আপলোডের পর থাম্বনেইল জেনারেট করা ভালো পদ্ধতি। এর জন্য কিছু অতিরিক্ত ধাপ দরকার।
থাম্বনেইল জেনারেট করা
ছবি ক্রপ ও স্কেল করার জন্য একটি আলাদা টুল লাগে। ক্যারিয়ারওয়েভ বিল্ট-ইনভাবে RMagick এবং MiniMagick জেম সাপোর্ট করে, যেগুলো ImageMagick-এর সাহায্যে ছবি ম্যানিপুলেট করে। ImageMagick একটি ওপেন-সোর্স সমাধান যা বিদ্যমান ছবি এডিট করতে এবং নতুন তৈরি করতে দেয়, তাই আগে এটি ডাউনলোড ও ইনস্টল করুন। তারপর দুটো জেমে যেকোনো একটি বেছে নিন। আমি MiniMagick পছন্দ করি কারণ এটি সহজে ইনস্টল হয় এবং ভালো সাপোর্ট পায়:
Gemfile
gem 'mini_magick'
চালান:
bundle install
তারপর আপলোডারে MiniMagick অন্তর্ভুক্ত করুন:
uploaders/image_uploader.rb
include CarrierWave::MiniMagick
এখন আপলোডারে একটি নতুন ভার্সন যোগ করুন। ভার্সন (অথবা স্টাইল) কনসেপ্ট অনেক ফাইল আপলোড লাইব্রেরিতে ব্যবহৃত হয়; এর মানে হলো মূল আট্যাচমেন্টের উপর ভিত্তি করে অতিরিক্ত ফাইল তৈরি করা—যেমন ভিন্ন ডাইমেনশন বা ফরম্যাটে। thumb নামে একটি ভার্সন যোগ করুন:
uploaders/image_uploader.rb
version :thumb do process resize_to_fill: [350, 350] end
আপনি চাইলে অনেক ভার্সন রাখতে পারেন, আরও একটি ভার্সন অন্য ভার্সনের ওপর ভিত্তি করে তৈরি করা যাবে:
uploaders/image_uploader.rb
version :small_thumb, from_version: :thumb do process resize_to_fill: [20, 20] end
যদি ইতিমধ্যে কিছু ছবি আপলোড করে থাকেন, তাদের থাম্বনেইল হবে না। সমস্যা নেই, রেইলস কনসোল থেকে পুনরায় তৈরি করা যাবে:
rails c
Post.find_each {|post| post.image.recreate_versions!(:thumb) if post.image?}
শেষে, থাম্বনেইলটি মূল ছবির লিংক সহ প্রদর্শন করুন:
views/posts/show.html.erb
<%= link_to(image_tag(@post.image.thumb.url, alt: 'Image'), @post.image.url, target: '_blank') if @post.image? %>
সার্ভার চালু করে ফলাফল দেখুন!
ভ্যালিডেশন যোগ করা
বর্তমানে আপলোডিং কাজ করছে, কিন্তু আমরা ইউজার ইনপুট ভ্যালিডেট করছি না, যা খুব খারাপ। আমরা শুধু ছবি নিয়ে কাজ করতে চাই, তাই .png, .jpg এবং .gif এক্সটেনশন হোয়াইটলিস্ট করব:
uploaders/image_uploader.rb
def extension_whitelist %w(jpg jpeg gif png) end
কন্টেন্ট টাইপ চেকও যোগ করা যায় content_type_whitelist মেথড দিয়ে:
uploaders/image_uploader.rb
def content_type_whitelist /image\// end
বা অন্য কিছু ফাইল টাইপ ব্ল্যাকলিস্ট করতে content_type_blacklist মেথড ডিফাইন করুন।
এক্সটেনশন ও টাইপ চেকের পাশাপাশি, ফাইল সাইজ ১ মেগাবাইটের নিচে রাখতে হবে। এর জন্য ActiveModel-এ ফাইল ভ্যালিডেশন সাপোর্টকারী একটি অতিরিক্ত জেম লাগবে:
Gemfile
gem 'file_validators'
ইনস্টল করুন:
bundle install
এখন প্রয়োজনীয় ভ্যালিডেশন যোগ করুন (এছাড়াও title এবং body-র জন্য চেকও যোগ করা হয়েছে):
models/post.rb
validates :title, presence: true, length: {minimum: 2}
validates :body, presence: true
validates :image, file_size: { less_than: 1.megabytes }
এবার ক্যারিয়ারওয়েভের এরর মেসেজের জন্য I18n অনুবাদ যোগ করুন:
config/locales/en.yml
en:
errors:
messages:
carrierwave_processing_error: "Cannot resize image."
carrierwave_integrity_error: "Not an image."
carrierwave_download_error: "Couldn't download image."
extension_whitelist_error: "You are not allowed to upload %{extension} files, allowed types: %{allowed_types}"
extension_blacklist_error: "You are not allowed to upload %{extension} files, prohibited types: %{prohibited_types}"
এখনও ভ্যালিডেশন এরর कहीं দেখানো হচ্ছে না, তাই একটি শেয়ার্ড পার্শিয়াল তৈরি করুন:
views/shared/_errors.html.erb
<% if object.errors.any? %>
<h3>Some errors were found:</h3>
<ul>
<% object.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
<% end %>
ফর্মে এই পার্শিয়াল ব্যবহার করুন:
views/posts/_form.html.erb
<%= render 'shared/errors', object: post %>
এখন কিছু ইনভ্যালিড ফাইল আপলোড করে ফলাফল দেখুন। কাজ করবে, কিন্তু যদি আপনি একটি বৈধ ফাইল বেছে নেন কিন্তু টাইটেল বা বডি না দেন, তবে চেক ফেইল করবে এবং এরর দেখাবে। কিন্তু ফাইল ফিল্ডটি ক্লিয়ার হয়ে যাবে এবং ইউজারকে আবার ছবি বেছে নিতে হবে, যা উপযুক্ত নয়। এটি ঠিক করতে ফর্মে একটি আরও ফিল্ড যোগ করতে হবে।
অনুরোধ জুড়ে ফাইল টিকে রাখা
ফর্ম পুনরায় প্রদর্শনের সময় ফাইল টিকে রাখা আসলে খুব সহজ। শুধু একটি হিডেন ফিল্ড যোগ করে কন্ট্রোলারে অনুমতি দিতে হবে:
views/shared/_form.html.erb
<%= f.label :image %> <%= f.file_field :image %><br> <%= f.hidden_field :image_cache %>
posts_controller.rb
params.require(:post).permit(:title, :body, :image, :image_cache)
এখন image_cache অটোমেটিকভাবে পপুলেট হবে এবং ছবি হারাবে না। থাম্বনেইলও দেখানো যাতে ইউজার বুঝতে পারেন ছবি প্রসেস হয়েছে:
views/shared/_form.html.erb
<% if post.image? %> <%= image_tag post.image.thumb.url %> <% end %>
ছবি মুছে ফেলা
রেকর্ড এডিট করার সময় আট্যাচ করা ফাইল মুছে ফেলার ক্ষমতা একটি সাধারণ ফিচার। ক্যারিয়ারওয়েভ দিয়ে এটি সহজেই ইমপ্লিমেন্ট করা যায়। ফর্মে একটি চেকবক্স যোগ করুন:
views/shared/_form.html.erb
<% if post.image? %>
<%= image_tag post.image.thumb.url %>
<div>
<%= label_tag :remove_image do %>
Remove image
<%= f.check_box :remove_image %>
<% end %>
</div>
<% end %>
এবং remove_image অ্যাট্রিবিউট অনুমতি দিন:
posts_controller.rb
params.require(:post).permit(:title, :body, :image, :remove_image, :image_cache)
বস! ম্যানুয়ালি ছবি মুছে ফেলতে remove_image! মেথড ব্যবহার করুন:
@post.remove_image!
রিমোট লোকেশন থেকে আপলোড করা
ক্যারিয়ারওয়েভ একটি খুব কুল ফিচার বিল্ট-ইন দেয়: URL দিয়ে রিমোট লোকেশন থেকে ফাইল আপলোড করা। এখন একটি নতুন ফিল্ড যোগ করে এটি ইমপ্লিমেন্ট করুন এবং সংশ্লিষ্ট অ্যাট্রিবিউট অনুমতি দিন:
views/shared/_form.html.erb
<%= f.text_field :remote_image_url %> <small>Enter URL to an image</small>
posts_controller.rb
params.require(:post).permit(:title, :body, :image, :remove_image, :image_cache, :remote_image_url)
ততটুকুই! কোনো পরিবর্তন ছাড়াই এই ফিচার টেস্ট করতে পারবেন!
একাধিক আপলোড নিয়ে কাজ করা
মান লें আমরা চাই পোস্টের একাধিক আট্যachment থাকে। বর্তমান সেটআপে এটি সম্ভব নয়, কিন্তু خوشবিশেষ ক্যারিয়ারওয়েভ এই সিনেরিওও সাপোর্ট করে। এটি ইমপ্লিমেন্ট করতে আপনাকে একটি সিরিয়ালাইজড ফিল্ড (SQLite-এর জন্য) বা JSON ফিল্ড (PostgreSQL বা MySQL-এর জন্য) যোগ করতে হবে। আমি JSON ফিল্ড পছন্দ করি, তাই ডাটাবেস অ্যাডাপ্টার পরিবর্তন করি। Gemfile- থেকে sqlite3 জেম বাদ দিয়ে pg যোগ করুন:
Gemfile
gem 'pg'
ইনস্টল করুন:
bundle install
ডাটাবেস কনফিগারেশন এভাবে মডিফাই করুন:
config/database.yml
default: &default adapter: postgresql pool: 5 timeout: 5000 development: <<: *default database: upload_carrier_dev username: 'YOUR_USER' password: 'YOUR_PASSWORD' host: localhost
PostgreSQL ডাটাবেস তৈরি করুন, তারপর মাইগ্রেশন জেনারেট ও প্রয়োগ করুন:
rails g migration add_attachments_to_posts attachments:json rails db:migrate
SQLite-এ থাকতে চাইলে ক্যারিয়ারওয়েভের ডকুমেন্টেশন ফলো করুন।
এখন আপলোডারগুলো মাউন্ট করুন (বহুবচন ফর্মে নোট করুন!):
model/post.rb
mount_uploaders :attachments, ImageUploader
আমি আট্যাচমেন্টের জন্য একই আপলোডার ব্যবহার করছি, কিন্তু আপনি ভিন্ন কনফিগারেশনের সাথে নতুন আপলোডারও জেনারেট করতে পারেন।
ফর্মে মাল্টিপল ফাইল ফিল্ড যোগ করুন:
views/shared/_form.html.erb
<div> <%= f.label :attachments %> <%= f.file_field :attachments, multiple: true %> </div>
attachments ফিল্ডে অ্যারে থাকবে, তাই কন্ট্রোলারে এভাবে অনুমতি দিন:
posts_controller.rb
params.require(:post).permit(:title, :body, :image, :remove_image, :image_cache, :remote_image_url, attachments: [])
শেষে, পোস্টের আট্যাচমেন্টগুলো ইটারেট করে 평소ভাবেই দেখান:
views/shared/show.html.erb
<% if @post.attachments? %>
<ul>
<% @post.attachments.each do |attachment| %>
<li><%= link_to(image_tag(attachment.thumb.url, alt: 'Image'), attachment.url, target: '_blank') %></li>
<% end %>
</ul>
<% end %>
নোট করুন, প্রতিটি আট্যাচমেন্টের থাম্বনেইল থাকবে যেন আমাদের ImageUploader-এ কনফিগার করা। খুব বাড়িয়া!
ক্লাউড স্টোরেজ ব্যবহার করা
ফাইল স্টোরেজে আটকে থাকা সবসময় সুবিধাজনক বা সম্ভব নয়—উদাহরণস্বরূপ হারোকুতে কাস্টম ফাইল স্টোর করা যায় না। তাই প্রশ্ন হতে পারে ক্যারিয়ারওয়েভকে আমাজন S3 ক্লাউড স্টোরেজের সাথে কীভাবে জোড়া দিতে হবে? সেটাও খুব সহজ। ক্যারিয়ারওয়েভ fog-aws জেমের ওপর নির্ভর করে এই ফিচার ইমপ্লিমেন্ট করতে:
Gemfile
gem "fog-aws"
ইনস্টল করুন:
bundle install
ক্যারিয়ারওয়েভের জন্য একটি ইнициয়ালাইজার তৈরি করুন এবং ক্লাউড স্টোরেজ গ্লোবালি কনফিগার করুন:
config/initializers/carrierwave.rb
CarrierWave.configure do |config|
config.fog_provider = 'fog/aws'
config.fog_credentials = {
provider: 'AWS',
aws_access_key_id: ENV['S3_KEY'],
aws_secret_access_key: ENV['S3_SECRET'],
region: ENV['S3_REGION'],
}
config.fog_directory = ENV['S3_BUCKET']
end
অন্যান্য অপশনও ডকুমেন্টেশনে পাওয়া যাবে।
আমি dotenv-rails জেম ব্যবহার করি এনভায়রনমেন্ট ভেরিয়েবল সিকিউরলি সেট করতে, কিন্তু আপনি অন্য অপশনও বেছে নিতে পারেন। তবে নিশ্চিত করুন যে আপনার S3 কি পেয়ার পাবলিকলি উপলব্ধ নয়, অন্যথায় কেউ আপনার বাকেটে যেকোনো কিছু আপলোড করতে পারবে!
এখন storage :file লাইনটি এভাবে প্রতিস্থাপন করুন:
uploaders/image_uploader.rb
storage :fog
S3-এর পাশাপাশি, ক্যারিয়ারওয়েভ Google Storage এবং Rackspace-ও সাপোর্ট করে। এগুলোও সহজে সেট আপ করা যায়।
উপসংহার
আজকের জন্য এটুকুই! আমরা ক্যারিয়ারওয়েভের সব বড় ফিচার কভার করেছি, এবং এখন আপনি আপনার প্রজেক্টে এটি ব্যবহার শুরু করতে পারেন। এতে আরও কিছু অপশন আছে, তাই ডকুমেন্টেশন ব্রাউজ করুন।
যদি আপনি আটকে যান, প্রশ্ন পোস্ট করতে সংকোচ ন করুন। ক্যারিয়ারওয়েভের উইকিও দেখতে পারেন, যেখানে অনেক সাধারণ প্রশ্নের উত্তর রয়েছে।
আমার সাথে থাকার জন্য ধন্যবাদ, এবং শুভ কোডিং!