I’m making a url shortener as a learning exercise. In addition to a Visit model (which isn’t important for this question), it has a Url and a Link model, which I have joined with associations. The Url class belongs to Link, and the Link class has_one :url.
In short, the problem is that when I call the shorten method in the Link class (from the create method in the Url controller), I’m getting this error message
undefined method `link' for #<ActiveRecord::Relation:0x00000102f648b8>
The application trace points to this line in the ‘shorten’ method of the Link class (copied below)
return url.link if url
So, I understand this error to mean that I can’t call ‘link’ on ‘url.’ However, I thought that the associations I created would allow me to do so. Can you explain what I’m doing wrong
Relevant Code
Form in new
<%= simple_form_for @url do |f| %>
<%= f.input :original, :label => 'Original Link', :input_html => { :maxlength => 70 } %>
<%#= f.input :custom, :label => '(Optional) Create your own custom shortened link ' %>
<%= f.button :submit %>
<% end %>
Create method url controller
def create
@url = Url.new(params[:url])
@link = Link.shorten(@url)
respond_to do |format|
if @url.save
format.html { redirect_to action: "index", notice: 'Url was successfully created.' }
format.json { render json: @url, status: :created, location: @url }
else
format.html { render action: "new" }
format.json { render json: @url.errors, status: :unprocessable_entity }
end
end
end
Url Class
class Url < ActiveRecord::Base
attr_accessible :original
belongs_to :link
end
Link class with shorten method
class Link < ActiveRecord::Base
attr_accessible :identifier
has_one :url
has_many :visits
def self.shorten(original, custom=nil)
url = Url.find_by_original(original)
return url.link if url #this is the problem line
link = nil
if custom
raise 'Someone has already taken this custom URL, sorry' unless Link.find(:identifier => custom).nil? #this Link.find
raise 'This custom URL is not allowed because of profanity' if DIRTY_WORDS.include? custom
transaction do |txn|
link = Link.new(:identifier => custom)
link.url = Url.create(:original => original)
link.save
end
else
transaction do |txn|
link = create_link(original)
end
end
return link
end
You are passing
@urltoLink.shortenbefore it is created. So you are calling thelinkmethod on a nil object.You need to place it after
@url.saveif you want it to work.