Useful Ruby Methods For Sinatra (possibly, most likely, also for Rails)
After spending more time on a Sinatra project than humanly necessary, I came across a few Ruby methods I believe are very useful in creating an app that fulfills the basic requirements of CRUD (Create, Read, Update, and Delete), and then some. Some of these methods make it easier for the programmer to navigate through the multiple files and folders in a more seamless manner, and others allow for better user flow throughout the app in the browser.
Before continuing, I want to give the obligatory link to restular, which provides near perfect templates you can use to begin writing out your controllers, routes, and basic coding practices.
Helper methods are useful tools that should be stored in the main controller for your application, aptly named ApplicationController
. Since all your other controllers are going to be inheriting from this one, it’s going to be a good idea to set methods here that can be accessed globally throughout your app.
configure do
set :public_folder, 'public'
set :views, 'app/views'
enable :sessions
set :I'm not showing you this
end
helpers do def logged_in?(session)
!!session[:user_id]
end def current_user
User.find_by(id: session[:user_id])
endend
The first helper method would be logged_in?(session)
. While some would argue that the parameter isn’t necessary, I think it is important for the data to be more clear to the method and another programmer, so an explicit declaration wouldn’t hurt. This method checks to see if the [:user_id]
of the sessions hash returns a truthy value, in other words, to check to see if it exists. If it does, we know that the user is currently the logged in active user on the app. Remember, a session is just Ruby’s way of storing user data in order to bypass HTTP’s inherent stateless form on the internet. It is stored so one request can be read again during subsequent requests.
The second method here is current_user
. I returned to this method many times in the app in different places such in the views when I couldn’t use an instance variable, as part of methods in other parts of my app in different controllers, and also in the layout.erb
file which dictates the way the app looks to the user. This method uses .find_by
to locate the user currently active in the sessions hash and sets itself as that user via their unique id. This allows the app to track this current user throughout the app, and any interactions the user makes with the website in regards to CRUD and other features is also stored as the session progresses.
post '/login' do
user = User.find_by(name: params[:name])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
redirect "/users/#{user.id}"
else
redirect '/login'
end
end
The .authenticate
method works in tandem with password_digest
which you will set your password
attribute as when migrating the Users
table, as well as the has_secure_password
method in the Users
model. This method checks to see if the password entered by the user matches the password originally set by the user, therefore gatekeeping whether or not the user can gain access to the account in question. Even though it will possibly be hashed or salted via bcrypt
, the method can decipher the changes and match the initial string value, making it the most useful tool for checking passwords.
patch '/items/:id' do
@item = Item.find(params[:id])
if current_user.id == @item.id
@item.assign_attributes(params[:item])
if @item.save
redirect '/items'
else
erb :'items/edit'
end
else
redirect '/items'
end
end
The .assign_attributes
method will allow you to set (in this case, change) attributes of an object by passing in a hash of attributes with keys matching the attribute names. So if the name of an item instant object was originally DR-1, you can change it to DR-2. To do so would require a form, which took me quite a while to hammer down the details of, so please see below.
<div class="item form">
<h1>Edit Your Item</h1>
<div><form action="/items/<%=@item.id%>" method="post">
<input type="hidden" name="_method" value="patch"><div class="form-group"><label>Name</label>
<input type="text" class="form-control" name="name"
required value="<%=@item.name%>"><br><label>Description</label>
<input type="text" class="form-control" name="description"
required value="<%=@item.description%>"><br><label>Item Image URL</label>
<input type="text" class="form-control" name="item_image_url" required value="<%=@item.item_image_url%>"><br></div><button type="submit" class="btn btn-primary">Submit</button>
</form><p><a href="/items/<%=@item.id%>">Back to your account</a></p><p><form action="/items/<%=@item.id%>" method="post">
<input type="hidden" name="_method" value="delete">
<input type="submit" value="Delete Item">
</form></p></div>
You can see that there are actually two forms present in this edit view for items. The first corresponds with the patch
request in the ItemsController and the second corresponds with the delete
request, also in the same controller. The delete form is actually just a button that permanently removes the object in question from the database via the .destroy
method.
delete '/items/:id' do
@item = Item.find(params[:id])
if current_user.id == @item.user_id
@item.destroy
redirect '/items'
else
redirect '/items'
end
end
So I hope some of these methods were able to help you in formulating your application. In my opinion Sinatra is a basic version of Rails in some regards, so the methods themselves are going to be just as simplistic, but it is still a great way to prepare yourself for the larger Ruby framework.
You can check out my app here.
Always remember to floss your teeth and stay hydrated.