Gradient text with Ruby on Rails

In a previous post that I talked about backups, there was something cool that I did. The project had text images with gradient and the client asked to change it to some text that could be put on the back office. I had two options, the first given to me was to see which gradients were already on the images and have an input box that would have the same gradients. The other option after I thought a little bit more was to give the client the freedom to select her own colors.

I will create a simple Ruby on Rails project that will show the modification. The actual project was much more complex, it had other languages, many translations and that was the main reason why they wanted to change it to text. Some words in German would occupy all of the space and she wanted the ability to select the font size as well.

rails new gradient-text

I will keep the database as SQLite because there is no need to have a more powerful one like PostgreSQL or MySQL.

Let’s generate a model, then migrate it

bundle exec rails g model Advertise title title_font_size:integer  first_color last_color

bundle exec rails db:migrate

When generating a model when you do not declare the type of column is defaults to string.

The controller:

bundle exec rails g controller Advertises index new create show edit update destroy

In the Rails “convention over configuration” doctrine the model defaults to singular and the controller as well as the views default to plural, see if you can understand why this makes sense. I’m sure you can 😉

This command generated lots of files and added the following routes to the config/routes.rb file:

Rails.application.routes.draw do
  get 'advertises/index'

  get 'advertises/new'

  get 'advertises/create'

  get 'advertises/show'

  get 'advertises/edit'

  get 'advertises/update'

  get 'advertises/destroy'
end

We will remove all of them and add the following:

Rails.application.routes.draw do
 root 'advertises#index'
 resources :advertises
end

The root method maps the index action on the controller to our pages’ index in this case locally will be http://localhost:3000
The resources :advertise will do the same as all the routes that were created by default by just using one single line of code.

Now we will work on the controller, this is how it is after generating it. Some work to do here.

class AdvertisesController < ApplicationController
  def index
  end

  def new
  end

  def create
  end

  def edit
  end

  def update
  end

  def destroy
  end
end

Becomes this:

class AdvertisesController < ApplicationController
  before_action :set_advertise, only: [:show, :edit, :update, :destroy]
  def index
    @advertises = Advertise.all
  end

  def new
    @advertise = Advertise.new
  end

  def create
    @advertise = Advertise.new(advertise_params)
    if @advertise.save
      redirect_to @advertise
    else
      render :new
    end
  end

  def show
  end

  def edit
  end

  def update
    if @advertise.update(advertise_params)
      redirect_to @advertise
    else
      render :edit
    end
  end

  def destroy
    @advertise.destroy
    redirect_to root_url
  end

  private
    def set_advertise
      @advertise = Advertise.find(params[:id])
    end

    def advertise_params
      params.require(:advertise).permit(:title, :title_font_size, :first_color, :last_color)
    end
end

The before action callback is called before any action on the controller is ran. In this case I only wanted it to be called when the user is editing, viewing, updating or destroying. Now you ask why is this? Well instead of repeating @advertise = Advertise.find(params[:id]) in each action, I just use that method and boom. There is a lot of controversy about callbacks in rails and that will be a topic of a next post.

Now the views are on the app/views/advertises

app/views/advertises/index.html.erb

<h1>Advertises</h1>
<table>
  <tr>
    <th>Title</th>
    <th>Font size</th>
  </tr>
  <% @advertises.each do |advertise| %>
    <tr>
      <td><%= advertise.title %></td>
      <td><%= advertise.title_font_size %></td>
      <td>
        <%= link_to 'Edit', edit_advertise_path(advertise) %>
        <%= link_to 'Show', advertise_path(advertise) %>
        <%= link_to 'Delete', advertise_path(advertise), method: :delete, data: { confirm: 'Are you sure?' }  %>
      </td>
    </tr>
  <% end %>
</table>

<%= link_to 'Create new advertise', new_advertise_path %>

app/views/advertises/new.html.erb

<h1>Creating a new Advertise</h1>

<%= form_for @advertise do |f| %>

  <%= f.label :title %>
  <%= f.text_field :title %>

  <%= f.label :title_font_size, 'Font size' %>
  <%= f.number_field :title_font_size %>

  <%= f.label :first_color %>
  <%= f.color_field :first_color %>

  <%= f.label :last_color %>
  <%= f.color_field :last_color %>

  <%= f.submit %>
<% end %>

app/views/advertises/show.html.erb

<p class="title-format"
   style='font-size: <%= @advertise.title_font_size %>px; background-image:
     linear-gradient(to right, <%= @advertise.first_color %>, <%= @advertise.last_color %>)'>
  <%= @advertise.title %>
</p>

<%= link_to 'Edit', edit_advertise_path %>

app/views/advertises/edit.html.erb

<h1>Editing a new Advertise</h1>

<%= form_for @advertise do |f| %>

  <%= f.label :title %>
  <%= f.text_field :title %>

  <%= f.label :title_font_size, 'Font size' %>
  <%= f.number_field :title_font_size %>

  <%= f.label :first_color %>
  <%= f.color_field :first_color %>

  <%= f.label :last_color %>
  <%= f.color_field :last_color %>

  <%= f.submit %>
<% end %>

Oh wait! Repeated code!? Worry not my friend, Ruby on Rails believes in D.R.Y. which means Don’t Repeat Yourself. We will move the form code to a partial and call it on each file.

touch app/views/advertises/_form.html.erb

app/views/advertises/_form.html.erb

<%= form_for @advertise do |f| %>

  <%= f.label :title %>
  <%= f.text_field :title %>

  <%= f.label :title_font_size, 'Font size' %>
  <%= f.number_field :title_font_size %>

  <%= f.label :first_color %>
  <%= f.color_field :first_color %>

  <%= f.label :last_color %>
  <%= f.color_field :last_color %>

  <%= f.submit %>
<% end %>

app/views/advertises/new.html.erb

<h1>Creating a new Advertise</h1>

<%= render 'form' %>

app/views/advertises/edit.html.erb

<h1>Editing an Advertise</h1>

<%= render 'form' %>

That’s the simplest way of using a partial.

And I almost forgot, the stylesheet that is on app/assets/stylesheets/advertise.scss

.title-format {
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

All of what I’ve done, just results on IE with a svg. You can get more info here

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s