Question

I have more curious questions for all you amazing people!

I am creating a forum and when you create a topic, you are also creating the first post at the same time.

I need to assign variables to certain fields.

Example: :user_id => current_user.id,

I don't have the param settings correct, so many of the fields are NULL when stored in the database.

Models

class Topic < ActiveRecord::Base
  belongs_to :forum
  has_many :posts, :dependent => :destroy  
  belongs_to :user
  accepts_nested_attributes_for :posts
end

class Post < ActiveRecord::Base  
  belongs_to :topic  
  belongs_to :user
end

Topics Controller

# GET /topics/new
def new
  @topic = Topic.new
  @topic.posts.build
end

def create  
  @topic = Topic.new(topic_params)

  if @topic.save 
    #@topic.responses = Post.new(params[:responses])
    flash[:success] = "Topic Posted"
    redirect_to "/forums/#{@topic.forum_id}" 
  else  
    render :new  
  end   
end

def topic_params
  # last_post_at = (:last_post_at => Time.now)
  params.require(:topic).permit(
    :name, 
    :description, 
    [:last_poster_id => current_user.id], 
    [:last_post_at => Time.now], 
    [:user_id => current_user.id],
    :forum_id,
    posts_attributes: [:id, :content, :topic_id, :user_id => current.user.id] )
end

Post Controller

# GET /posts/new
def new
  @post = Post.new
end

def create  
  @post = Post.new(
    :content => params[:post][:content], 
    :topic_id => params[:post][:topic_id], 
    :user_id => current_user.id)  

  if @post.save  
    @topic = Topic.find(@post.topic_id)  
    @topic.update_attributes(
      :last_poster_id => current_user.id, 
      :last_post_at => Time.now)  
    flash[:notice] = "Successfully created post."  
    redirect_to "/topics/#{@post.topic_id}"  
  else  
    render :action => 'new'  
  end  
end  

_form for View/Topic

<%= form_for(@topic) do |f| %>
  <% if params[:forum] %>
    <input type="hidden" 
    id="topic_forum_id" 
    name="topic[forum_id]" 
    value="<%= params[:forum] %>" />
  <% end %>  

  <div class="field">
    <%= f.label :name %><br>
    <%= f.text_field :name %>
  </div>
  <div class="field">
    <%= f.label :description %><br>
    <%= f.text_field :description %>
  </div>

  <%= f.fields_for :posts do |p| %>

    <%= p.label :content %><br />
    <%= p.text_area :content %>

  <% end %>
  <%= f.submit :class => "btn btn-primary" %>
<% end %>
Was it helpful?

Solution

You'll likely be looking for a function called:

accepts_nested_attributes_for

You put this into the model you're working with (in your case Post) and it will pass paeans for the nested model through to the corresponding controller

There is a good RailsCast about this and I've gr some experience with it too. If you want me to post working live code, let me know (I'm on my iPhone)


Live Code

Models

#app/models/image_post.rb
belongs_to :post, :class_name => 'Post'
belongs_to :image, :class_name => 'Image'
accepts_nested_attributes_for :image, :allow_destroy => true

#app/models/post.rb
has_many :images, -> { uniq }, :class_name => 'Image', :through => :images_posts, dependent: :destroy
has_many :images_posts, :class_name => 'ImagePost'
accepts_nested_attributes_for :images_posts, :allow_destroy => true

Controller

    def new
            @post = Post.new
            @post.images_posts.build.build_image
    end

    def create
            #Using Inherited Resources Gem
            create! 
    end

    private
    def permitted_params
            {:post => params.require(:post).permit(:title, :body, images_posts_attributes: [:caption, image_attributes: [:image]] )}
    end

Form

<%= form_for [:admin, resource], :html => { :multipart => true }  do |f| %>
        <table class="resource_table">
                <thead>
                        <th colspan="2"><%= params[:action].capitalize %> <%= resource_class %></th>
                </thead>
                <tbody class="form">
                        <% attributes.each do |attr| %>
                                <tr class="<%= cycle('odd', '')%>">
                                        <td><%= resource_class.human_attribute_name(attr) %></td>
                                        <td>
                                                <% if attr == "body" %>
                                                        <%= f.text_area attr, :rows => 60, :cols => 80, :class => "redactor" %>
                                                <% else %>
                                                        <%= f.text_field attr, :value => resource.public_send(attr).to_s %>
                                                <% end %>
                                        </td>
                                </tr>
                        <% end %>
                        <%= f.fields_for :images_posts do |images_posts| %>
                                <%= images_posts.fields_for :image do |images| %>
                                        <tr>
                                                <td>Image</td>
                                                <td><%= images.file_field :image %></td>
                                        </tr>
                                <% end %>
                                <tr>
                                        <td>Caption</td>
                                        <td><%= images_posts.text_field :caption %></td>
                                </tr>
                        <% end %>
                        <tr class="dull">
                                <td colspan="2"><%= f.submit "Go" %></td>
                        </tr>
                </tbody>
        </table>
<% end %>

OTHER TIPS

Use accepts_nested_attributes

class topic
 accepts_nested_attributes :posts
end

class post
  accepts_nested_attributes :topic
end

Then in form you can use fields_for posts while creating topic form Also in post form fileds_for for topic

You may want to fetch the post params as

params[:topic].fetch(:post_attributes, nil)

Rails 4 has been sanitized the mass-assignment to be called as strong_params Example

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top