Find & Replace Using Sed & Grep

by Jess Brown

I recently had a client who needed to change the phone number across the site. I didn't build the site, but I quickly found out the previous developer didn't use any variables or partials. The phone number was scattered throughout several hundred static files across the site.

Luckily I had shell access to the server, so I just needed a script to find and replace all the files.

I had already grep'ed the files which told me the phone number was littered throughout the site files:

grep -r 555-555-5555 ./

Now I just needed a way to replace that number with the new one. Sed to the rescue.

grep -rl 555-555-5555 | xargs sed -i 's/555\-555\-5555/444\-444\-4444/g'

There you go, several hundred files changed at once.

Small Design Suggestion For 37signals Blog

by Jess Brown

I just recently redeisgned my blog and one of the blogs I drew inspiration from was the 37Signals Blog Signal vs. Noise.

So I'm fairly familer with their styles (font, size, color, width, line-height, etc). One thing I noticed today while reading an article was their images seem off alignment:

Off alignment image

I'm not sure if this was intentional or an oversight (or maybe the writer forgot to apply a class), but I figured I'd write it up and tweet it out to see if my sugggestion would be well received.

The issue is on their paragraphs, they have a text-indent set:

.post-content p + p {
  text-indent: 2em;
}

For most of their images on this page, they're the first and only content in the paragraph tag, so the images are being indented too, which causes the left edge to be indented, but also the right edge to push past the normal paragraph's width.

They could override the paragraph's text-indext for the image like this:

.post-content p img {
  margin-left: -2em;
}

This will negate the 2em paragraph indent and slide the image over even with the left and right sides of the paragrahp text:

Images Fixed

Simple Rails Blogging With Vim & Markdown

by Jess Brown

I've had a wordpress blog for about 5 years. I've never really been serious about blogging, which is a real shame because I've learned so much about rails and web development over the years, there's tons I could have shared (plug for anyone to start blogging). Anyhow, over the last year or two, I've really wanted to get more into blogging and writing. There's so much potential that can come from it. Learning more about the topic you're writing about, communication skills, building an audience, marketing, SEO, building credibility, are just a few to start. I was recently listing to the ThoughtBot podcast and heard an interview with Nathan Berry where he discussed his goal of writing 1000 words everyday and also talked about building an audience. I was inspired and decided I had to get something started.

However, my geek side wanted something cool and convenient to write with. I'm a vim user, love markdown, and am loyal to git, so I knew I wanted to use those tools. My known options were pretty much limited to, Octopress, Jekyll, and Middleman. I'd tried Octopress and Jekyll before and didn't really get along with them (was also inexperienced with them) and I never really gave Middleman a chance. Before middleman came out, I was using and contributing to Serve a lot and I just didn't want to relearn Middleman. I just kept asking myself, "I'm a rails developer, why can't I use rails to blog?" I also had some notions to maybe add some functionalty for things like client login, intergrate my time tracker, invoicing, etc, and rails would have been my obvious choice for that.

Well, I finally came across a gem called postmarkdown. It's a "A simple Rails blog engine powered by Markdown". So I tried it out and I was hooked on making it work.

My website and blog are opensourced so I hope you'll check out out. I'll give the details on my blogging workflow below.

Fire up my terminal and to create a new post:

rails generate postmarkdown:post my-new-title

That generates a markdown file in app/posts. Then I open in vim and like to use a vim plugin called Goyo for a write-room like experience:

Goyo Screenshot

After finishing writing, it's just:

git commit ...
rake deploy

I could (and probably will) write a lot more about what's going on behind the scenes technically, but I mainly just wanted to give a brief overview on the setup and about a developer trying to make a habit of writing!

Until later, free to use the github repo to play around with.

Let me know if you have any questions.

Allow Admin To Log On As Another User In A Rails App

by Jess Brown

In a lot of the apps I build, I continue to assist the users of the app with technical support help.

In some apps it makes sense to build a backend admin interface where we have separate controllers and views and even design. Other apps we may use an open source gem like ActiveAdmin.

However, in some cases, it just helps to be able to see what the user sees. If you've ever tried to help someone pair, troubleshoot a technical issue, setup an email account, etc, you'll know that there's no substitute for being able to share screens and see what they're seeing.

I just recently implemented the ability for an admin to log into a user's account and wanted to share to

  1. see if anyone thought there was any issue/danger in doing this
  2. Hopefully help anyone do the same (as long as #1 is ok :-)

So here's how I did it:

So a user with the admin role has a view to see a list of all authors (my user in this case was an author). Next to each author's name is a link to sign in as the author.

The Routes:

resources :impersonates, only: [:create, :destroy]

A controller:

class ImpersonatesController < ApplicationController
  load_and_authorize_resource :author, :only => :create

  def create
    authorize! :impersonate, @author
    session[:admin_logged_in] = current_user.id
    sign_out current_user
    sign_in @author
    redirect_to dashboard_author_path(@author), :notice => "Signed in as #{@author.name}"
  end

  def destroy
    if session[:admin_logged_in].present?
      if author_signed_in?
        sign_out current_author
      end
      user = User.find(session[:admin_logged_in])
      sign_in user
      session[:admin_logged_in] = nil
      redirect_to user, :notice => "Signed back in as admin"
    else
      redirect_to root_path
    end
  end
end

There are 2 basic actions: 1) admin can sign in as another author and 2) the admin can sign back in as admin (without having to reenter user/pass).

Authorization:

As you can see, I'm using cancan to authorize my controller actions. The main action of concern is the "author" action because that actually logs a user in as another user. We don't want that being exploited. We load and authorize the author that we want to log into. As you can see below, authors only have the ability to manage themselves. I add an extra layer of security authorize! :impersonate, @author that will prevent an author from being able to give themself the :admin_logged_in flag. So that should make it impossible for any non authorized users or guests to exploit the action.

One problem I ran into initially was after I was able to log into an author's account, I couldn't perform any 'admin' type actions because I was actually logged in as the author. To get around this, I passed in my session to my ability class and added the ability to :admin all actions if the :admin_logged_in session has was set. This allowed me to do this in the views: if can?(:admin, @author) ...

# app/controllers/application_controller.rb
# you need to override the current_ability method to pass in the session
def current_ability
  @current_ability ||= Ability.new(user, session)
end

# app/models/ability.rb
def initialize(user, session)
  user ||= User.new(:role => 'guest') # guest user (not logged in)
  admin_logged_in = session[:admin_logged_in]

  ....

  ## Authors
  can :manage, Author, :id => user.id
  cannot [:index, :impersonate], Author
  if admin_logged_in.present?
    can :admin, :all
  end

  ...

end

The views:

# the admin's list of authors
...
=link_to "Sign in as this author", impersonates_path(author_id: author.id), :method => :post

# the ability for the admin to sign back in as admin without having to
reenter credintials
...
- if session[:admin_logged_in].present?
  =link_to "Sign in as admin", impersonate_path("revert"), method: :delete

Tests

What good is code with tests? To keep the article a concise as possible, I left them out, but posted them here for your reference:

Impersonates User Tests

So that's pretty much it. Now the admin can sign in as an author, view

the app as the author, even perform some admin actions and then sign back in as the admin.

What do you think?


UPDATE:

I really appreciate Andy Lindeman and Jonathan Wallace reviewing my article and making some great suggestions:


Navigation