I ask myself when would I need to use a conditional validation. I could bypass certain validations based on a specific attribute being filled or not.
A big topic of late has been female founders not applying to accelerators/incubators like YC.
There are 60 posts filed in Uncategorized (this is page 3 of 6).
I ask myself when would I need to use a conditional validation. I could bypass certain validations based on a specific attribute being filled or not.
A big topic of late has been female founders not applying to accelerators/incubators like YC.
I was originally going to create the episode 40 blocks in view, but there was a comment mentioning that episode 208 was the updated version. I did watch episode 40 nonetheless, and I noticed how much Rails has improved. The way to create a block in view in Rails 2 was by concatenating
and using a block.binding
. This seems like a hack compared today’s Rails standard.
For comparison the code for episode 40
def admin_area(&block)
concat content_tag(:div, capture(&block), :class => 'admin'), block.binding if admin?
end
Episode 208
def admin_area(&block)
content_tag(:div, :class => "admin", &block) if admin?
end
The line for the episode 208 was shorter because it eliminated concat
capture()
and block.binding
. concat
was rendered unnecessary after ERB used the <%= %>
tag to signify whether or not the output would be rendered to the view. capture()
tried to capture the output of a block’s yield. The content_tag now is able to accept a block as an argument without the need for capture()
. block.binding
binds to the erb templating. I’m not sure why this became unnecessary, but I suspect the revision of erb fixed this.
Assets Precompile
While pushing to Heroku the CSS I wrote for the admin_area
was not being rendered. I eventually found the answer on StackOverflow. I did not have the rails_12factor gem. After further reading of the README for rails_12factor, rails_12factor allows static assets to be retrieved despite using a proxy like Nginx. A proxy like Nginx routes the asset path of assets/rails.png
to public/assets/rails.png
. Rails 4 is sort of encouraging the use of a CDN to host static assets. The Readme also linked to the ’12factor’ methodology which seems to touch on devops.
What I love about following the Railscasts and actually implementing the small features is that making these apps are quick, I’m exposed to something I wouldn’t have been otherwise, and they are straightforward. This episode was no different.
preview_button
<%= submit_tag 'Preview', name: 'preview_button' %>
The Preview button is similar to the the submit button, but it differs in it function. The name for the button defaults to commit
when using the submit_tag
helper. This is good when you need to create a normal submit button to create or update a record, but in the case of a preview button, you do not want to save the record just yet. Instead of having the name='commit
we override this default by specifying the name should be equal to preview_button
. With the name now equalling preview_button
the parameters hash has "preview_button" => "Preview"
.
Controller
def create
...
respond_to do |format|
if params[:preview_button] || !@project.save
format.html { render action: 'new' }
format.json { render json: @project.errors, status: :unprocessable_entity }
else
format.html { redirect_to @project, notice: 'Project was successfully created.' }
format.json { render action: 'show', status: :created, location: @project }
end
end
end
We can then use the params[:preview_button]
within our conditional in the create action. If params[:preview_button]
is not nil, then the controller will redirect to the new view while still having the preview_button
parameter present in the URL. If there is no params[:preview_button]
defined, then we know that the form was submitted through the normal submit button and not the preview button.
Textilize
<% if params[:preview_button] %>
<div id="preview">
<h2><%= @project.name %></h2>
<%= textilize @project.description %>
</div>
<% end %>
When we are redirected to the new
view, the params[:preview_button]
is still defined. We can use this in another conditional within our view to display a preview. Here we are previewing the project’s description using the textilize text helper. This was deprecated back in Rails 2, but I found a gem that dropped in to Rails 3+ that adds this back. There has to be a reason that the Rails Core Team deprecated this, so I do not plan to use this again. Instead I might reuse the code I used to render markdown to the view from my Markdown Todo List Rails API App
If you have a region highlighted, then you can either dedent or indent using the c-c <
or c-c >
respectively.
Form
<%= form_tag projects_path, method: :get do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag 'Search', name: nil %>
</p>
<% end %>
The form for the search form has many lessons to learn. The use of form_tag
over form_for
is preferred we are not updating attributes associated with a specific model. Here the form_tag
submits to the projects path. Normally when you submit a form using the form_for
or form_tag
Rails helper Rails create the html tags with a post method filled in. When you submit a post request to the projects path, Rails thinks you are trying to create a new record because of the RESTful design. To counteract this you have to explicitly specify the method used on this form, in this case get
.
Controller
def index
@projects = Project.search(params[:search])
end
Instead of the usual Project.all
, we use a search
method that we defined in the project
model. The search method accepts a argument that is matched with records in the database.
Model
class Project < ActiveRecord::Base
def self.search(search)
if search
if Rails.env.development?
where("name LIKE ?", "%#{search}%")
elsif Rails.env.production?
where("name ILIKE ?", "%#{search}%")
end
else
all
end
end
end
This is where most of the work is being done. Here we are defining a class method called search
which accepts one parameter. If this parameter is true, then it will search for a name similar to the search
argument. There is a conditional based on the environment because the LIKE
function in SQLite3 used in development is case insensitive, while the LIKE
function in PostgreSQL used in Production is case sensitive. PostgreSQL LIKE To counteract this, I have included the ILIKE
function for only the production environment.
The "%#{search}%"
confused me, so I asked on StackOverflow about what the %
was. Apparently it is SQL Wildcards used to match characters in a string. It is similar to how Regex pattern matches, but SQL Wildcards are much simpler. It appears there are only four syntaxes that can be used. %
, _
, []
, [^]
. The %
substitute zero or more characters. _
substitutes a single character. []
matches sets or ranges of characters. Example: [abc]%
matches anything that starts with abc. Similar to regex you use ^
to declared not
. [abc]%
matches anything that does NOT start with abc. Similar to Regex, so this was not too mind blowing. The tricky part was learning the syntax used.
I have been developing with Ruby on Rails and Emacs for a good three months now, but I haven’t been using the emacs editor to its full potential. Nothing illustrates that more than not using a Ruby on Rails minor mode like Rinari. I just enabled rinari-minor-mode today and watched the introduction Rinari Screencast, and I’m blown away at how much time I could be saving using come of the commands shown.
You could switch over to the controllers, models and views using the c-c ; f
c
, m
, or v
command keys. What I was really looking for was to make the erb <%= %>
tags, and the rinari minor mode can do that as well with c-c ' e
.
Cheatsheet
C-c ; f c rinari-find-controller
C-c ; f e rinari-find-environment
C-c ; f f rinari-find-file-in-project
C-c ; f h rinari-find-helper
C-c ; f i rinari-find-migration
C-c ; f j rinari-find-javascript
C-c ; f l rinari-find-plugin
C-c ; f m rinari-find-model
C-c ; f n rinari-find-configuration
C-c ; f o rinari-find-log
C-c ; f p rinari-find-public
C-c ; f s rinari-find-script
C-c ; f t rinari-find-test
C-c ; f v rinari-find-view
C-c ; f w rinari-find-worker
C-c ; f x rinari-find-fixture
C-c ; f y rinari-find-stylesheet
C-c ; s rinari-script
C-c ; e rinari-insert-erb-skeleton
C-c ; r rinari-rake
C-c ; w rinari-web-server
C-c ; x rinari-extract-partial
C-c ; ; rinari-find-by-context
C-c ; d rinari-cap
C-c ; q rinari-sql
C-c ; t rinari-test
C-c ; c rinari-console
C-c ; g rinari-rgrep
C-c ; p rinari-goto-partial
C-c ; ' rinari-find-by-context
more bindings can be seen with c-h b
. I just learnt about this command through the Rinari video. It is useful because you can see all the commands associated to different minor modes.
This is one of those episodes I needed to see. I haven’t had to use the collection or member blocks in the routes file before, but I’m glad to know what they mean now. member
and collection
allows the developer to create custom RESTful routes that extends the rails conventions. A member
route appends after the /:model/:id
, so the controller action has the params[:id]
. A collection
route appends after the /:model
route.
Examples of these two were the routes created in this episode.
resources :tasks do
get 'completed', on: :collection
put 'complete', on: :member
end
This creates the normal RESTful Rails routes, but it also create two custom routes. /tasks/completed/
and /tasks/:id/complete
. The Rails Guides for Routing was useful for further reading.
TasksController
def completed
@tasks = Task.where(completed: true)
end
def complete
@task.update_attribute :completed, true
flash[:notice] = 'Task Completed'
redirect_to completed_tasks_path
end
The two custom actions were completed
and complete
The completed
action returns a tasks instance variable where completed
is true. The complete
action updates an attribute to true, then redirects to the completed tasks view with a flash notice.
To complete a task, the episode shows creating a link with the put method being sent the complete_task_path
while sending the task’s id.
Heroku Issue
For some reason when I tried to click on this ‘complete task’ link, heroku is giving me a ‘page doesn’t exist’ error. Locally the link works however. I have opened a StackOverflow question about the issue. I don’t think you need a view for that action because it redirects to the completed_tasks_path. Even the rake routes show a PUT for /tasks/:id/complete
. I did discover that the Rails core team has been switching over to the Patch
verb over the put
http verb. This adheres to RFC specification for partial updates. Even though I tried to change out put
for patch
, I was unable to get this link working.
This episode was essentially repeated in Railscast 016 Virtual Attributes. Despite it being a repeat, I decided to create a project for this Railscast because the following episode, 033, used it to make a Rails Plugin. Rather than make the plugin, I wanted to try creating my second RubyGem based on this plugin.
Although I was not aware of this while making the gem, there was another person who had the same idea. His gem is called jakewendt-stringify_time, but it hasn’t been updated four years. The gem I created integrates with the changes made to the Ruby on Rails framework since that gem’s creation.
Because this would be my second gem I have created, I thought I could just model this gem similarly to my first gem body_id. I created the basic gem files using bundle gem stringify_time
command. Then I edited the .gemspec
file to put in the basic information needed. The part I got confused about was at the part I was going to use railtie
. The Railscast simply extended ActiveRecord using the module created in the plugin. Instead of following my previous gem, I decided to try how it was made in the video. I copied the StingifyTime
module from the episode and extended ActiveRecord just like it was shown in the episode. I ran rake release
and had version 0.0.1
on RubyGems.org. That’s when I created the previous project from Episode 032 to try the gem out. The bad part was, it didn’t work.
After some searching around I noticed other gems did not use extend
method on ActiveRecord directly, but they used the .send :include, StringifyTime
method to call the include method on a module. So I tried to exchange
ActiveRecord::Base.extend StringifyTime
with
ActiveRecord::Base.send :include, StringifyTime
The problem was I blindly tried to copy and try this method without fully understanding why I was using include
instead of extend
. Include is used on an instance of a class to add methods, while extend is used to add methods to the class itself. At the same time, I searched my gem on RubyGems.org and discovered the Jake Wendt’s gem based on the same episode. I looked at his GitHub Repo and saw he had an init.rb
and rails/init.rb
. “Could this solve it?”, I thought. I applied the changes, and the stringify_time
method was being include in my rails app.
Metaprogramming
What is so interesting about creating this stringify_time
method is that you are writing a program in order to have it write another program. That’s the concept of metaprogramming at least. You could have defined each getter and setter method manually, but that isn’t practical when you have numerous attributes you need to do the same thing on. I have used metaprogramming when I made a seed.rb
file to fill up the database with records. These methods saves a lot of time if made correctly.
Unresolved
When I went to edit the date on the form, the date was not updating. This is still a problem I need to solve, and I have opened a question on StackOverflow to try to resolve this issue. While I wait for an answer I’ll keep moving to another Railscast.
Update
Someone on StackOverflow suggested I try using the generated method via the Rails console. I tried to use the rails console, and the due_at
attribute was updated. I thought why was I able to update the attribute in the console, but not via the form. The answer was because I was not whitelisting the :due_at_string
param in the task_params
definition. This is to protect from mass assignment. So the data from the form was never reaching the model because it was being prevented by the controller. A silly mistake to overlook.
This gem was created following the Rails plugin made in Railscast 033 Making a Plugin.
Add this line to your application’s Gemfile:
gem 'stringify_time'
And then execute:
$ bundle
Or install it yourself as:
$ gem install stringify_time
Within an the model add stringify_time
passing in a symbol that you want to set as the attribute you want aliased as a virtual attribute string.
class Task < ActiveRecord::Base
stringify_time :due_at
end
This will create the due_at_string
getter and setter methods within the Task model. You can then access this attribute in the views like so:
_form.html.erb
<%= form_for @task do |f| %>
...
<div class="field">
<%= f.label :due_at %><br>
<%= f.text_field :due_at_string %>
</div>
...
<% end %>
Your users are now able to type in the date into a text field instead of using the Rails’ default datetime_select
dropdowns.
After using git version control for sometime, you may notice yourself running git status
multiple times right before you commit. Like the programmers we are, we are inherently lazy. in a good way. Instead of typing git status
numerous times a day, type gits
.
Here’s line you’ll need to alias it in the bash terminal
alias gits='git status'
Add this line to either you ~/.bashrc
or ~/.bash_profile
. Remember to reload bash again by opening a new terminal window so bash can import this alias.
Bonus
alias gita='git add'