Devise Username Authentication With Multiple Models And Subdomains

Posted January 24, 2012 under Rails

Devise is an awesome library for authentication with Rails. Things are extremely simple to setup for most cases but when you begin implementing slightly trickier business logic, it can become a pain. And the real reason is mainly just because the wiki needs a little love. They iterate quickly, and documenting everything in a newbie friendly wiki page is often hard to do. So I’m going to take a quick stab at documenting my implementation:

The Problem

I’m working on an application that runs on multiple domains and subdomains. Each domain has it’s own set of admins and users. The admins are tied to a domain, and users are tied to a subdomain of that domain. Both of these need to allow authentication via a username field as opposed to the standard email field.

Starting out, we implemented the models just like normal with Devise. Generate custom views for each, and follow this tutorial for adding username authentication.

After I got everything setup, admin users could login just fine, but users could not. What was worse, was the Devise Sessions controller was executing but never calling find_for_database_authentication on the model. I had no idea what was going on, and all I could get Devise to do was return a Completed 401 Unauthorized error and immediately re-render the login form.

This is where we differentiate a bit. In that tutorial, they suggest that you set the authentication_keys in devise.rb like this:

  config.authentication_keys = [ :login ]

Well this is actually going to be the source of our problems. In order to authenticate admins based upon a specific domain, we’re going to include the domain_id inside of the login form as a hidden field. In order to use the domain_id inside the model for authentication, we added it to the authentication_keys array:

  config.authentication_keys = [ :login, :domain_id ]

But wait! That works for admins because they are based upon the domain. Users authenticate against a subdomain, not a domain_id. The users need authentication_keys like this:

  config.authentication_keys = [ :login, :subdomain_id ]

And we put the subdomain_id as a hidden field in their new session form. This is a problem, because the initializer only runs once. We need some way to change this at runtime based upon which type of user is authenticating.

The solution

After a long time searching for a solution to the 401 Unauthorized, I found out that the authentication_keys was the cause of the problem (after having a hunch). The bad part was that I wasn’t able to find a method for debugging the issue.

I found the solution on Stack Overflow that pointed out that you’re actually able to set authentication_keys on the model itself in the devise call like so:

  devise :database_authenticatable, :registerable, ..., :authentication_keys => [:login, :domain_id]

Nifty! We can set these dynamically without touching the initializer. This lets us cleanly customize the authentication without much work. I’ll be updating the wiki to add this functionality because I certainly can’t be the only one who searched long and hard for a solution!


Happiness Leads To Success, Not The Other Way Around

Posted January 23, 2012 under General


Gary Vaynerchuck Keynote at Inc 500

Posted January 16, 2012 under General

I love it. Gary V has so much enthusiasm and drive. What a great talk as always!


Remove Autocomplete URLs From Chrome

Posted January 10, 2012 under General

At some point yesterday I was doing my usual email checking. It’s a habit I have when I’m not sure what to do: I hit the keyboard shortcut for opening a new tab and type “g” and hit enter. I’ve opened up GMail enough times with this shortcut that it always autocompletes first.

However, something I ended up doing yesterday submitted just the letter “g” instead. Now every time it autocompletes that to my Charter search. Horrible.

If you need to remove a website from Chrome’s autocomplete suggestions, it’s really simple:

Fn + Shift + Delete while highlighting the website you want to remove

Simple as that. I’ve also read just Shift + Delete works if you’re not on a Mac. Do you have any other protips?


Year in Review: 2011

Posted December 30, 2011 under General

As usual, it’s hard to believe another year has come and gone. Unlike past years, I feel more accomplished. I took some leaps of faith this year and have to admit, those were the best moments of my life. Here are a few lessons I learned throughout the year.

I Graduated College

As a student I was too protected. If I messed up I could retake the class. If I didn’t have much money, I could get student loans. If I didn’t want to work on a team project, I could have someone on my team who was more driven do my part for me if I procrastinated enough. I had parents who were always willing to buy me food and clothes when I came home to visit. Worst case scenario? I could fail out and live with my parents. There was nothing to be afraid of, and yet, because there was no challenge, nothing at risk, I was more depressed than I had ever been in my life.

Even now, I’m too protected. The experience of college wasn’t what I wanted. I didn’t fit in. Against better judgement, I stayed. I didn’t want to feel rejected by parents and family for dropping out. I regret not taking the jump and quitting. Everything is 20/20 in retrospect. Things would have worked out had I quit college, but in the moment there is always so much uncertainty.

I learned that lesson the hard way. Through the worrying and depression, I learned a lot about myself. I learned that I need a constant challenge. I learned that I absolutely love writing (I may not be good at it yet, but at least I enjoy it). Sure, I got a degree and met a handful of great people who I will always consider friends, but I didn’t have the experience I had expected.

The best part about it? I realized that if I don’t truly enjoy what I’m doing, it’s not worth my time. Life is too short to do things you hate. Instead of telling everyone “I’ll be happy in X years when I can get such and such job” I have it right now.

This is different for everyone, of course. Not everyone enjoys risk the same way. Some people love being comfortable and I respect that. The important part is to learn who you are. Embrace it. Then find ways to improve yourself.

Got A Job I Love

People have asked me how I liked my new job. I get to build web apps every day, something I’ve dreamed of for quite a while. Often I’ll respond with “I haven’t worked a day since I started.” They are sometimes confused by that response. But why? Aren’t they doing something they absolutely love? Sadly, most of them are not. They are stuck in the system, and sadly, some of them may never realize they can break out of this rut.

The “system” that we have to follow? Turns out it’s all bullshit. 1) Go to college 2) Get a job 3) Save some money 4) ???? 5) Finally go enjoy life

Steve Jobs put it best:

So ask yourself, are you doing what you love? If you say “Well I’m just doing this until…” then YOU are caught in the system. Think about it. Do some soul searching. You only have a few years on this planet. Make the most of it.

Formed Good Habits

This year, as I began to better understand myself, I decided it would be good to start picking up some better habits. Every morning I do a set of pushups and sit-ups. Every night I read a couple chapters of a book. Not blogs. A book. Something that went through editing several times. Something more than just a late night rant on a blog somewhere.

And then it all stopped. I went home for the weekend and broke my habit. It’s a dreadful feeling. I was doing so good, and yet, getting backup on the horse seems so hard again. Guess what? It’s not. Just like the pomodoro technique, you’ve just got to try again. It’s not as hard as you think. Your mind likes to play tricks on you. Things seem worse than they really are. It makes you think that picking up a book every night is hard for some reason.

Start a new habit. You know it’s good for you, so don’t break that habit. No. matter. what. Eventually it will become routine and you will feel weird not doing it. The best things in life aren’t always easy. Sometimes it takes a lot of hard work and determination. Your mind is the problem with these things. Know that you can conquer it.

The Flinch is a really good book about pushing your boundaries and doing the things you know you should be doing. Read it several times if you have to. There is no reason that you can’t become the person you want to be. It’s all in your head.

Conclusion

Over the past year, I think the majority of what I learned was who I am as a person. I have plenty of flaws. I’m not perfect. The best realization I had this year was exactly that. I’m not perfect, but I can now be conscious of that. I can fix my flaws. I can improve myself. Nothing says I have to continue being “who I am.” No. I can challenge myself. I’ll never stop learning, but what I will stop doing is things I don’t enjoy. There’s not enough time for that. I don’t have to follow the system. It’s just there as a guideline.

“Here’s to the crazy ones. The misfits. The rebels. The troublemakers. The round pegs in the square holes. The ones who see things differently. They’re not fond of rules. And they have no respect for the status quo. You can quote them, disagree with them, glorify or vilify them. About the only thing you can’t do is ignore them. Because they change things. They push the human race forward. And while some may see them as the crazy ones, we see genius. Because the people who are crazy enough to think they can change the world, are the ones who do.” – Steve Jobs


Rails Tip #4: Rails Time Select Like Google Calendar

Posted December 22, 2011 under General

Something that has always bothered me is the way we input dates and times on the web. It’s still not pretty yet. It’s bad. jQuery plugins and large calendar might be alright for dates, but times? They still suck horribly.

Look at what Rails gives us by default for a date and time selector:

That is just nasty. It’s a 24 hour time selector and separated into separate fields. The iPhone/iPad have a nice little spinner, but that’s only useful if you have a touch screen. Google Calendar’s time picker so far has been my favorite. I wanted to emulate that and found a nice little library that did what I wanted.

It’s not a magical solution, but it works well enough:

Awesome! But then I realized, nobody really maintained this anymore. And on top of that, there was no good solution for using the value returned. It’s not in the params name that works well the built-in Rails form.

Announcing combined_time_select

I spent some time on this because a combined time select field is something I want to use quite often. The following is an example of how you would use the gem in both the view and the controller. It works cleanly with the date_select field on the same attribute.

The parse_time_select converts the params into a Time object so that we can assign it to an attribute easily. It is, of course, not required if you would like to do the time parsing yourself.

Check out combined_time_select on Github: github.com/excid3/combined_time_select

Or install it with Bundler:

  gem "combined_time_select", "~> 0.0.1"

If you have any questions, comments, or ideas let me know!


Rails Tip #4: Seedbed

Posted December 15, 2011 under General

Depending on your project, you might need to create a significant amount of seed data. Upon launch, you’ll probably need your team setup as admin users, get some content up on the site so it doesn’t look like a barren wasteland.

Sure, I know how to do that. I’ll just slap it all into db/seeds.rb!

That’s fine…if you’re only create a handful of things. Say you want to organize things? Say you want folders? Say you want to only run certain seeds?

In Comes Seedbed

Seedbed allows you to create files in the db/seeds/ directory that you can run either individually or you can “plant” them in seeds.rb.

Take this for example:

Here we’ve got a seed that creates only Admin users. With seedbed, we can put this file inside db/seeds/ and then execute it like so:

rake db:seed:admins

How cool is that? Say we’re playing around with features and need to truncate the Admin Users table locally. We can repopulate the admins very simply without recreating the whole set of seeds.

You can even add them to db/seeds.rb to automatically run the nested seeds themselves:

plant :admins

And run the rake db:seed command as normal to automatically run all of the custom seed files.

Seedbed on Github


Maybe Your Life Is Too Easy

Posted December 13, 2011 under General

Yesterday I was watching this TED talk and I was truly impressed by her story.

What I realized after watching this was that the reason her story is amazing, it is because she had faced incredible challenges. It’s rare for anyone to tell a story like this who has been given everything. In fact, I can’t think of a single story like that.

Amy was more depressed than I can probably imagine but she turned things around and became a snowboarder. The guys at Airbnb were dead broke and they created cereal boxes in order to raise money to survive. Even looking back in my own life, one of my best programming accomplishments was because I was trying to live on dialup.

There are many many stories like this. And here you sit, dreaming about what things you’d like to accomplish. If only you had lots of money. If only you had this or that. If only.

You’ve probably always been living an “easy” life. Think about it. You’ve got all your limbs, good family and friends. Your parents bought you a car when you turned sixteen. Your parents paid for college. But yet, you’ve never been happy with your grades, your relationships, your job, or where you wanted to be at this point in life? Maybe it’s because things are too easy.

Maybe you need to try something completely different for a while. Risk it all, see what happens. The flinch of doing something different might be the reason you are holding back.

It’s easy to take things for granted. Soon enough you are making a steady paycheck living an easy life and then what? You become boring.

“Hey how have you been?”
Oh just busy working/studying/whatever.

“That’s cool. I just got back from mountain climbing in the alps.”
Wow! That’s awesome! I wish I could do things like that.

Well why the hell not? I even look at my friend Willis and am constantly impressed with his entrepreneurship. While he will be the first to tell you that he has no idea what he is doing, I’m still impressed none the less.

Sometimes you need to take a leap of faith and risk what you’ve got. After all, you’ve probably got more than lots of other people on this planet. Can you live without your television, fancy kitchen utensils, and heated blankets? Absolutely. Then make a bet on yourself. If you don’t do something you have always wanted to do in the next month, you’ll sell your TV. Have someone else hold you accountable. Push your boundaries.

I know I have gotten far too comfortable with my life. Sleeping late, off to work in the mornings, have a nice dinner, kick back and watch a movie, go to bed, rinse and repeat. But I feel terrible about it. I’m not progressing towards much. Things are too comfortable right now. I know that I’m stalled in my progression, but it’s time to move on. To get back in that groove. No more being comfortable. Things are too easy.

The last thing I want is to look back on my life and regret how I spent my time. I’m looking at you Skyrim:

So to start off, I’m making a list of things I want to accomplish in the next year and having my friend hold me to it. What are some life experiences you’ve had and wish more people tried?


Long Walks Are My Evening Long Showers

Posted December 9, 2011 under General


This might be a post more for myself than for others, but hey, I started this blog to keep track of my own thoughts. I’m just happy if anyone gets a nugget of help or inspiration.

Lately I haven’t been feeling as good as usual. The time change makes the sun set incredibly early now. I picked up the Elder Scrolls: Skyrim and basically didn’t go outside for a week and a half. I stopped working out. I stopped my evening reading. It was terrible.

But I think I’ve beaten it. Everyone knows that some of our best thinking gets done in the mornings in the shower. It’s awesome. I’ve talked myself through a lot of complicated things before. After realizing that I was losing track, I wondered how I could fix this downward spiral.

My solution? Talking long walks. I’ll walk for at least half an hour. Nowhere in particular. The fresh air, the atmosphere of the city, the bustling the strangers walking down the street. All of these things I don’t get at the office or at home for extended periods of time.

Sure, I’m probably more prone to depression than some people. My mom is like this, my grandparents, and so on. It’s beatable, but the wrong thing to do is worry. I can sit there staring my email all night and get nothing done, or I can go relax for a bit and then come back and work hard for an hour productively.

At the end of the day things can feel pretty awful. You had a bad day at work, relationship problems, whatever. My solution is to go take a walk. Think about it. Think if it is really that bad. Chances are it isn’t. Make sure to take time out of the day for yourself to think and be detached.

Quit worrying about things so much. It will always work out in the end. No happiness ever comes out of worrying.


Rails Tip #3: Annotate

Posted December 8, 2011 under General

As you jump between Rails projects, you’ll quickly realize that you end up checking the database schema to see which attributes your model has. This can get annoying to say the least, and that’s what the Annotate gem aims to solve.

It’s a quick install in your Gemfile:

gem "annotate", "~> 2.4.0", :group => :development

Afterwards, just run bundle install and you’re ready to go. Just type annotate in terminal inside your rails application directory and it will generate comments in your models that look similar to this:

class LineItem < ActiveRecord::Base
  belongs_to :product
end 
 
# == Schema Info
#
# Table name: line_items
#
#  id                  :integer(11)    not null, primary key
#  quantity            :integer(11)    not null
#  product_id          :integer(11)    not null
#  unit_price          :float
#  order_id            :integer(11)
#  created_at          :datetime
#  updated_at          :datetime
#

And there you go! You’re able to easily reference what columns each model. While it’s not anything groundbreaking, it saves me a couple minutes every day.


« Older |