Search code examples
ruby-on-rails-4model-associationsslugfriendly-id

Rails: Associating two different models when not using params[:id]


I have two models Author and Post. I want an author to be able to create posts and have an association between those two models. I normally do this by nesting author and posts so the url would look like author/:id/posts. In this case, I use params[id] to find the Author and everything works. However, this time, I want the posts to appear on their on own like /posts/name-of-post and the same with authors; they would appear as author/name-of-author. To create the slugs I'm using the friendly_id gem. I have the slug working on the author controller. However, I can't find a way to create a post and create the association.

Please help me create the post and associate it to the author.

Author model

class Author < ActiveRecord::Base
  has_many :posts

  validates :name, :slug, presence: true

  extend FriendlyId
  friendly_id :name, use: :slugged
end

Post model

class Post < ActiveRecord::Base
  belongs_to :author
end

Author Controller

def new
  @author = Author.new
  respond_with(@author)
 end
private
def set_author
  @author = Author.friendly.find(params[:id])
end

def author_params
  params.require(:author).permit(:name, :slug, :bio)
end

Post Controller

def new
  @post = Post.new
  respond_with(@post)
end
def create
  @post = Post.new(post_params)
  @post.save
  respond_with(@post)
end
private
def set_post
  @post = Post.find(params[:id])
end

def post_params
  params.require(:post).permit(:title, :body, :slug, :author_id)
end

Post _form (slim)

= form_for @post do |f|
- if @post.errors.any?
#error_explanation
  h2 = "#{pluralize(@post.errors.count, "error")} prohibited this post from being saved:"
  ul
    - @post.errors.full_messages.each do |message|
      li = message

.field
  = f.label :title
  = f.text_field :title
.field
  = f.label :body
  = f.text_area :body
.field
  = f.label :slug
  = f.text_field :slug
.field
  = f.label :author
  = f.text_field :author

.actions = f.submit 'Save'

The associations work fine when I try them on the console. My problem is that I can't get the id of the author to de automatically populated on the new post form view and create the relationship when I save the new post.


Solution

  • You'll want to create the post the same way you were creating posts before. The fact that you want to be able to see a post individually, unconnected to an author, doesn't need to change how you created them.

    So, for example, for the url /author_slug/posts/new, your controller actions might look like:

    # posts_controller.rb
    def new
      @author = Author.friendly_find(params[:author_id])
      @post = @author.posts.build
    end
    

    Then, on your authorless route of posts/post-slug-from-friendly-id, you'd just need to get the author from the post. Something like:

    # routes.rb
    get 'posts/:post_slug', to: posts#anonymous_show
    
    # posts_controller.rb
    def anonymous_show
      @post = Post.friendly_find(params[:post_slug])
      @author = @post.author
    end