Search code examples
ruby-on-railsrubyauto-generate

Rails, how to change automatic generated link


I have a RoR app. And in app users can create posts. I've connected Posts table in my routes.rb via resources :posts. And right now - link to created post look like: http://mysitename.com/posts/1 (where 1 is post number).

What i want to do, is to make rails generate link to post. So users didn't see how much posts I have in my DB. And as result it must look like http://mysitename.com/post/generatedlink. It must generate, for example post theme.

For start, we must create link column in Posts table. And make it to generate something like that:

@post.link = @post.theme.parameterize.underscore 

But I don't understand, where to put this code.

And the next problem is: "How to replace post/1 for @post.link?"

Hope, I make my self clear. If you'll say I can provide information, what is needed to resolve my question.

UPDATE

What I did after @SteveTurczyn advise.

I've created new column, called random_link as a string.

I didn't touch my routes.rb:

resources :posts

My post.rb (post model) look like this:

after_validation  :add_link 

def add_link
  self.random_link = self.theme.to_slug_param 
  # to_slug_param it's a gem for translating from other language into english
end

def to_param
  random_link
end

I don't have find method. My posts_controller.rb look like this:

def show
  @post = Post.find_by_random_link(params[:id])
  right_menu_posts
  random_link_to_other_post(@post)
end

  private 

  def random_link_to_other_post(post)
    random_post = Post.where.not(id: post.id)
    @random_post = random_post.sort_by {rand}.first
  end

  def right_menu_posts
    @posts_for_video_in_right_menu = Post.where(video: true)
  end

And html.erb:

<%= @post.theme %>
<%= @post.content %>

<% for post in @random_post %>
  <%= link_to post %>
<% end %>
<% for post in @posts_for_video_in_right_menu %>
  <%= link_to post %>
<% end %>

And on a main page (where i have a list of posts) a keep getting an error: NoMethodError in Home#index private method 'to_param' called for #<Post:0x007fae3096bf78>.


Solution

  • The technique is referred to as slugifying and you need to do three things...

    (1) create a new field called slug in your posts table.

    (2) add this code to your Post model...

    after_validation :generate_slug
    
    private
    
    def generate_slug
      self.slug = theme.parameterize.underscore
    end
    
    public
    
    def to_param
      slug
    end
    

    (3) finally, in your controllers where you have find_post methods, rewrite it to be...

    def find_post
      Post.find_by_slug(params[:id])
    end
    

    The to_param method in the model is how things like post_path(@post) build the url... the to_param if not replaced substituted the id field but by writing your own to_param method you can ensure that the slug field is substituted instead.

    Ensure that 'to_param' is a public method! Don't put it in the private part of your model. You can do that by putting public immediately before the to_param method. You should then put private after the method definition if subsequent methods are to be private.