Welcome to this lesson! Today, we will be implementing the file-uploading functionality in our Ruby on Rails ToDo application. This is an important feature as it allows users to upload files related to their ToDo items. Files might include images, documents, or other relevant attachments, enhancing the functionality and user experience of our app.
In this lesson, we will cover the basics of file uploading in Ruby on Rails and integrate this capability into our ToDo app using the TodosController
. By the end of this lesson, you should be able to create an endpoint that handles file uploads and links the uploaded files to specific ToDo items.
Before diving into file uploading, let's quickly recap the setup we have so far in our ToDo application. This will ensure that we are all on the same page and ready to add new functionality.
Here is a summary of our TodoService
, which handles various actions such as fetching all ToDo items, fetching a specific item by ID, creating new items, updating an item, and deleting an item:
Ruby1class TodoService 2 @todos = [] 3 4 def self.create(todo_params) 5 todo = { id: @todos.size + 1, **todo_params } 6 @todos << todo 7 todo 8 end 9 10 def self.get_all 11 @todos 12 end 13 14 def self.get_by_id(id) 15 @todos.find { |todo| todo[:id] == id.to_i } 16 end 17 18 def self.update(id, todo_params) 19 todo = get_by_id(id) 20 todo[:title] = todo_params[:title] if todo_params[:title] 21 todo[:description] = todo_params[:description] if todo_params[:description] 22 todo 23 end 24 25 def self.delete(id) 26 @todos.reject! { |todo| todo[:id] == id.to_i } 27 end 28end
Before we start coding, it's crucial to understand how file uploading works in Ruby on Rails. Rails provides an intuitive way to handle file uploads through its robust framework. When we upload a file via an HTML form, the file is transmitted in a multipart/form-data
request. Rails makes it easy to access this file and perform various operations, such as saving it to a directory.
Handling file uploads typically involves:
Let's implement the file upload endpoint in our TodosController
. We will add an upload
action that handles the file upload process. Here's the code:
Ruby1def upload 2 uploaded_file = params[:file] 3 filepath = Rails.root.join('public', uploaded_file.original_filename) 4 File.open(filepath, 'wb') do |file| 5 file.write(uploaded_file.read) 6 end 7 todo = TodoService.add_file(params[:id], uploaded_file.original_filename) 8 render json: todo 9end
Breaking it down step-by-step:
Access the uploaded file:
Ruby1uploaded_file = params[:file]
We retrieve the file from the request parameters using params[:file]
.
Define the file path:
Ruby1filepath = Rails.root.join('public', uploaded_file.original_filename)
We create a file path where the file will be stored. Rails.root
gives us the root directory of the application, and we join it with public
and the original file name to create the complete path.
Save the file:
Ruby1File.open(filepath, 'wb') do |file| 2 file.write(uploaded_file.read) 3end
We open the file in write-binary mode ('wb'
) and write the content of the uploaded file to it.
Update the ToDo with the file info:
Ruby1todo = TodoService.add_file(params[:id], uploaded_file.original_filename)
We call the add_file
method in the TodoService
to link the file to the specific ToDo item by its ID.
Return the updated ToDo item:
Ruby1render json: todo
Finally, we render the updated ToDo item as a JSON response.
Now, let's integrate our file-handling functionality with the TodoService
. The service layer will handle the business logic for associating the uploaded file with a ToDo item. Here's the add_file
method in the TodoService
:
Ruby1class TodoService 2 def self.add_file(id, filename) 3 todo = get_by_id(id) 4 todo.update(file: filename) 5 todo 6 end 7end
Explanation:
get_by_id(id)
to find the specific ToDo item by its ID.todo.update(file: filename)
. This assumes that our Todo
model has a file
attribute to store the file name.Since file uploading is not included in the default Rails RESTful actions, we must explicitly configure our routes to incorporate the upload
action within the TodosController
. To do this, open the config/routes.rb
file and modify it to add the upload
action as a member route of the todos
resource:
Ruby1Rails.application.routes.draw do 2 resources :todos do 3 member do 4 post 'upload' 5 end 6 end 7end
In this configuration:
resources :todos
defines the standard RESTful routes for the todos
resource.member do
block adds a custom route for the upload
action, which will be accessible via a POST request to /todos/:id/upload
, where :id
is the ID of the specific ToDo item.With these routes in place, our application can handle file uploads for individual ToDo items, linking each uploaded file to its corresponding ToDo item by ID.
In this lesson, we covered:
upload
action in the TodosController
.TodoService
.With this knowledge, you are now prepared to implement file uploading in your own ToDo application. Proceed to the next practice exercises to get hands-on experience with the concepts covered in this lesson. Keep experimenting and exploring, as this will solidify your understanding and prepare you for more advanced topics in future units.
Happy coding!