Search code examples
ruby-on-railsrubyform-helpers

Creating Rails Form


I'm trying to create a form in rails but I'm getting the following error:

undefined method `[]' for nil:NilClass
Extracted source (around line #1):
1  <%= form_for @url do |f| %>
2    <p>
3      <label>Create an new Short URL now - </label>
4    </p>

new.html.erb

<%= form_for @url do |f| %>
  <p>
    <label>Create an new Short URL now - </label>
  </p>
  <p>
    <%= f.text_field :url %>  
  </p>
  <p>
    <%= f.submit %>
  </p>


<% end %>

home_controller.rb

class HomeController < ApplicationController

  def index

  end

  def about
  end

  def new
    @url = ShortUrl.new
  end    

  def show
    url = params[:id]
    @url = ShortUrl.where(["url = ?", url]).first

    if @url.nil?
      redirect_to home_index_path
    else
      redirect_to @url.full_short_path
    end
  end    
end

short_url.rb

require 'uri'
require 'googl'
class ShortUrl < ActiveRecord::Base
  attr_reader :url, :host, :scheme
  attr_accessor :url_length    
  validates_presence_of  :url, :host, :scheme    
  validates_uniqueness_of :url, :host, :scheme
  VALID_CHARS = (('a'..'z').to_a << (0..9).to_a).flatten

  private 
  attr_accessor :gmail_config
  public

  def initialize
  end

  def setup(url)
    uri = URI.parse(url)
    @host = uri.host
    @scheme = uri.scheme
    @length = url.length/3
    @gmail_config = AML.load_file("#{Rails.root.to_s}/config/gmail_secrets.yml")[Rails.env]
    @url = get_random_string
  end

  def full_short_path
    scheme + host
  end    

  private    

  def get_short_url
    client = Googl.client(@gmail_config['address'], @gmail_config['password'])
    url = client.shorten(full_short_path).short_url
  end    

end

Solution

  • You're sub classing active record. DO NOT overwrite initialize, you need to delete that. AR implements it for you. You can also remove any of the attr_accessor and attr_reader attributes that are database columns. Rails handles this for you.

    You'll want to avoid multiple private & public sections as well. Put private/protected sections near the bottom. Here's my re-write of your model:

    require 'uri'
    require 'googl'
    class ShortUrl < ActiveRecord::Base
      attr_reader :url, :host, :scheme
      attr_accessor :gmail_config, :url_length
      validates_presence_of  :url, :host, :scheme
      validates_uniqueness_of :url, :host, :scheme
      VALID_CHARS = (('a'..'z').to_a << (0..9).to_a).flatten
    
      def setup(url)
        uri = URI.parse(url)
        @host = uri.host
        @scheme = uri.scheme
        @length = url.length/3
        @gmail_config = AML.load_file("#{Rails.root.to_s}/config/gmail_secrets.yml")[Rails.env]
        @url = get_random_string
      end
    
      def full_short_path
        scheme + host
      end    
    
    private    
    
      def get_short_url
        client = Googl.client(@gmail_config['address'], @gmail_config['password'])
        url = client.shorten(full_short_path).short_url
      end    
    
    end
    

    Note that you do not want to have an attr_accessor call in private. a) it does nothing, and b) the whole point of it is to make instance variables @url for example public.