Rails 4: Nested objects not saving to database - ruby-on-rails-4

I'm building a forum and I have forum_types that has_many forum_threads. I want to show a list of the different forum threads a forum type has when clicked. I can create a forum thread for a forum type but it's not showing on the forum thread 'index' page (forum_type_forum_threads_path). There is no error, just a blank page where I have placed the loop. I feel like it's something in my forum_threads_controller. If someone could please help me I would appreciate it...thanks in advance.
forum_threads_controller.rb
class ForumThreadsController < ApplicationController
before_action :require_user, except: [:show, :index]
before_action :set_forum_type
before_action :set_forum_thread, except: [:index, :new, :create]
def index
#forum_threads = ForumThread.all #something not right here
end
def show
#forum_post = ForumPost.new
end
def new
#forum_thread = ForumThread.new(params[:id])
#forum_thread.forum_posts.build
end
def create
#forum_thread = current_user.forum_threads.new forum_thread_params
#forum_thread.forum_posts.first.user_id = current_user.id
if #forum_thread.save
flash[:success] = "Your thread has been created."
redirect_to forum_type_forum_thread_path(#forum_type, #forum_thread)
else
render action: :new
end
end
private
def set_forum_type
#forum_type = ForumType.find(params[:forum_type_id])
end
def set_forum_thread
#forum_thread = ForumThread.find(params[:id])
end
def require_same_user
if current_user != #forum_thread.user
flash[:danger] = "You can't do that."
end
end
def forum_thread_params
params.require(:forum_thread).permit(:subject, :description, forum_posts_attributes: [:id, :body])
end
end
forum_types_controller.rb
class ForumTypesController < ApplicationController
before_action :set_forum_type, except: [:index, :new, :create]
def index
query = params[:q].presence || "*"
#forum_types = ForumType.search(query, suggest: true)
end
def show
#forum_type.forum_threads.each
end
def new
#forum_type = ForumType.new
end
def create
#forum_type = ForumType.new(forum_type_params)
if #forum_type.save
flash[:success] = "Forum created."
redirect_to forum_types_path
else
render action: :new
end
end
def destroy
#forum_type = ForumType.find(forum_type_params[:id]).destroy
end
def search
index
render :index
end
private
def set_forum_type
#forum_type = ForumType.find(params[:id])
end
def forum_type_params
params.require(:forum_type).permit(:title, forum_thread_attributes: [:id, :subject,
{ forum_post_attributes: [:id, :body] }])
end
end
views/forum_threads/index/html.erb
<h2><%= #forum_type.title %></h2>
<hr />
<%= link_to "New Thread", new_forum_type_forum_thread_path(#forum_type.id), class: 'btn btn-primary' %>
<% #forum_type.forum_threads.each do |forum_thread| %>
<div class="panel panel-default">
<div class="panel-body">
<h4><%= link_to forum_thread.subject, forum_type_forum_thread_path %>
<small><strong>Created by </strong>
<%= link_to forum_thread.user.name, user_path(forum_thread.user.id) if forum_thread.user %>
<%= local_relative_time(forum_thread.created_at, { type: 'time-ago', class: 'pull-right' }) %>
</small>
</h4>
</div>
</div>
<% end %>
views/forum_types/index.html.erb
<%= render 'shared/page_title', title: "Forums" %>
<%= link_to "New Forum Type", new_forum_type_path, class: 'btn btn-primary' %>
<% #forum_types.each do |forum_type| %>
<div class="panel panel-default">
<div class="panel-body">
<%= link_to forum_type.title, forum_type_forum_threads_path(forum_type.id) %>
</div>
</div>
<% end %>
models/forum_type.rb
class ForumType < ActiveRecord::Base
has_many :forum_threads
accepts_nested_attributes_for :forum_threads
has_many :forum_posts, through: :forum_threads
accepts_nested_attributes_for :forum_posts
validates :title, presence: true
end
models/forum_thread.rb
class ForumThread < ActiveRecord::Base
belongs_to :user
belongs_to :forum_type
has_many :forum_posts
accepts_nested_attributes_for :forum_posts
validates :subject, presence: true
validates_associated :forum_posts
end
routes.rb
resources forum_types do
resources forum_threads do
resources forum_posts
end
end
If you need anymore files let me know.

Added/removed some lines in create action of the forum threads controller. Then passed in the "#forum_type" and "forum_thread" after the link_to button in the view.
forum_threads_controller.rb
class ForumThreadsController < ApplicationController
before_action :require_user, except: [:show, :index]
before_action :set_forum_type
before_action :set_forum_thread, except: [:index, :new, :create]
def index
# #forum_threads = ForumThread.all
forum_threads = #forum_type.forum_threads.all.order("#{:created_at} DESC")
end
def show
#forum_post = ForumPost.new
end
def new
#forum_thread = ForumThread.new
#forum_thread.forum_posts.build
end
def create
#forum_thread = #forum_type.forum_threads.new(forum_thread_params)
#forum_thread.user = current_user
#forum_thread.forum_posts.first.user = current_user
if #forum_thread.save
flash[:success] = "Your thread has been created."
redirect_to forum_type_forum_thread_path(#forum_type, #forum_thread)
else
render action: :new
end
end
private
def set_forum_type
#forum_type = ForumType.find(params[:forum_type_id])
end
def set_forum_thread
#forum_thread = ForumThread.find(params[:id])
end
def require_same_user
if current_user != #forum_thread.user
flash[:danger] = "You can't do that."
end
end
def forum_thread_params
params.require(:forum_thread).permit(:subject, :description, forum_posts_attributes: [:id, :body])
end
end
views/forum_threads/index.html.erb
<%= render 'shared/page_title', title: #forum_type.title %>
<div class="col-md-9">
<%= link_to "New Thread", new_forum_type_forum_thread_path(#forum_type.id), class: 'btn btn-primary' %>
<% #forum_type.forum_threads.each do |forum_thread| %>
<div class="panel panel-default">
<div class="panel-body">
<h4><%= link_to forum_thread.subject, forum_type_forum_thread_path(#forum_type, forum_thread) %>
<small><strong>Created by </strong>
<%= link_to forum_thread.user.name, user_path(forum_thread.user.id) if forum_thread.user %>
<%= local_relative_time(forum_thread.created_at, { type: 'time-ago', class: 'pull-right' }) %>
</small>
</h4>
</div>
</div>
<% end %>
</div>
<%= render 'sidebar' %>

Related

Rails 4 Nested Form not Passing Nested Attributes in Params

When I submit the form it is passing {"utf8"=>"✓", "authenticity_token"=>"blah", "client"=>{"first_name"=>"jack", "last_name"=>"kool","complaints"=>{"symptom"=>"burnt"} in the params and I am getting Unpermitted Parameters: complaints Since complaints is nested in Client, it should be passing complaints_attributes, like I have it set up in the strong params, and I can't figure out why it isn't.
class ClientsController < ApplicationController
def new
#client = Client.new
end
def edit
#client = Client.find(params[:id])
end
def create
#client = Client.new(client_params)
if #client.save
redirect_to #client
else
render 'new'
end
end
def update
#client = Client.find(params[:id])
if #client.update(client_params)
redirect_to #client
else
render 'edit'
end
end
private
def client_params
params.require(:client).permit(:first_name, :last_name, complaints_attributes: [ :symptom, :id ])
end
end
Client model:
class Client < ActiveRecord::Base
has_many :complaints
has_one :personal_disease_history
has_one :family_disease_history
has_many :surgeries
has_many :hospitalizations
has_many :medications
has_many :allergies
validates :first_name, :last_name, presence: true
accepts_nested_attributes_for :complaints
end
Complaint model:
class Complaint < ActiveRecord::Base
belongs_to :client
end
Form:
<%= form_for :client, url: clients_path, html: { class: "form-inline" } do |f| %>
<div class="panel panel-success">
<div class="panel-heading">
<h3 class="panel-title">Health History Form</h3>
</div>
<div class="panel-body">
<div class="form-blocks"><legend>Name</legend>
<div class="form-group">
<%= f.label :first_name, class: "sr-only" %>
<%= f.text_field :first_name, class: "form-control", placeholder: "First Name" %>
</div>
<div class="form-group">
<%= f.label :last_name, class: "sr-only" %>
<%= f.text_field :last_name, class: "form-control", placeholder: "Last Name" %>
</div>
</div>
<div class="form-blocks"><legend>Complaints</legend>
<div class="form-group">
<%= f.fields_for :complaints do |builder| %>
<%= builder.label :symptom, class: "sr-only" %>
<%= builder.text_field :symptom, class: "form-control", placeholder: "Symptom" %>
<% end %>
</div>
</div>
<div>
<%= f.submit "Submit Form", class: "btn btn-primary btn-lg"%>
</div>
<% end %>
inside client controller create action, try saying this inside the if #client.save:
Complaint.create(symptom: params[
"client"]["complaints"]["symptom"], client_id: #client.id)
the unpermitted parameter is related to the nested attribute problem but this should get the actual record saving. If that doesn't do it, please post the stack trace surrounding the commit.
have couple other ideas: but (1) you have complaint_attributes in the permitted params but you could change that to complaint bc that's what's coming through in the params.

Inexplicable unpermitted parameters error in Rails 4 nested form

I've searched high and low, and found many posts similiar, but can't seem to debug the following code.
I have a project model, which has many many teams. It has many users through teams. Here are the relevant models.
project.rb
class Project < ActiveRecord::Base
has_many :teams
has_many :users, :through => :teams
accepts_nested_attributes_for :teams
end
team.rb
class Team < ActiveRecord::Base
belongs_to :project
belongs_to :user
end
user.rb
class User < ActiveRecord::Base
has_many :teams
has_many :projects, :through => :teams
end
projects_controller.rb
class ProjectsController < ApplicationController
def index
#projects = Project.all
end
def new
#project = Project.new
end
def create
#project = Project.create(project_params)
redirect_to projects_url
end
def show
#project = Project.find(params[:id])
end
def edit
#project = Project.find(params[:id])
end
def update
#project = Project.find(params[:id])
#project.update(type_params)
redirect_to project_url
end
def destroy
#project = Project.find(params[:id])
#project.destroy
redirect_to projects_url
end
end
private
def project_params
params.require(:project)
project_params = params.require(:project).
permit(:name, :code, :description, :externalId,
{:teams_attributes => [:id, :userId, :projectId]})
end
I have a nested form, that should allow me to create a new project and one team (just typing in the ID), however I get an unpermitted parameters exception ("Unpermitted parameters: team")
Whenever I submit the form. Form code is below.
new.html.erb
<h1>Create New Project</h1>
<%=form_for(#project) do |f| %>
<p>
<%=f.label "Name"%>
<%=f.text_field :name%> <br>
<%=f.label "Code"%>
<%=f.text_field :code%> <br>
<%=f.label "External ID"%>
<%=f.text_field :externalId%> <br>
<%=f.label "Description"%>
<%=f.text_field :description%> <br>
</p>
<ul>
<%= f.fields_for :team do |tf| %>
<li>
<%= tf.label 'User Id' %>
<%= tf.text_field :userId %>
<%= tf.label 'Project Id' %>
<%= tf.text_field :projectId %>
</li>
</ul>
<%end%>
<%=f.submit%>
<%end%>
I've paid special attention to the permitted parameters fields, and think I got them right, but, rails disagrees.
Any help would be appreciated
Your nested form doesn't work with has_many because it is singluar. You want to use f.fields_for :teams do instead (plural). Please try the following changes:
project_controller.rb
def new
#project = Project.new
#project.teams.build
end
[...]
private
[...]
# Never trust parameters from the scary internet, only allow the white list through.
def project_params
params.require(:project).permit(:name, :code, :externalId, :description, teams_attributes: [ :user_id, :project_id ])
end
new.html.erb
<h1>Create New Project</h1>
<%=form_for(#project) do |f| %>
<p>
<%=f.label "Name"%>
<%=f.text_field :name%> <br>
<%=f.label "Code"%>
<%=f.text_field :code%> <br>
<%=f.label "External ID"%>
<%=f.text_field :externalId%> <br>
<%=f.label "Description"%>
<%=f.text_field :description%> <br>
</p>
<ul>
<%= f.fields_for :teams do |tf| %>
<li>
<%= tf.label 'User Id' %>
<%= tf.text_field :user_id %>
<%= tf.label 'Project Id' %>
<%= tf.text_field :project_id %>
</li>
<%end%>
</ul>
<%=f.submit%>
<%end%>
Change this method like this and try
private
def project_params
params.require(:project)
project_params = params.require(:project).
permit(:name, :code, :description, :externalId,
{:teams_attributes => [:id, :userId, :projectId]})
end
to
private
def project_params
params[:project].permit(:name, :code, :description, :externalId,
{:teams_attributes => [:id, :userId, :projectId]})
end

NoMethodError in Posts#show undefined method `post_comments_path'

I used associations in the models whenever I am applying associations I am getting problem ,I am new to ruby as well as rails.I am using Rails4,Eclipse,Windows Xp(sp3) and mysql5.6 ,I am getting the above error when I want clicked the show link the error is
undefined method `post_comments_path' for #<#<Class:0x2aef820>:0x2bd7df8>
Extracted source (around line #25):
<h2>Add a comment:</h2>
<%= form_for([#post, #post.comments.build]) do |f| %>...here it is line number 25
<p>
<%= f.label :commenter %><br />
<%= f.text_field :commenter %>
I have two model
post.rb
class Post < ActiveRecord::Base
has_many :comments
validates :title, presence: true,
length: { minimum: 5 }
end
comment.rb
class Comment < ActiveRecord::Base
belongs_to :post
end
I have two controllers
posts_controller.rb
class PostsController < ApplicationController
def new
#post=Post.new
end
def show
#post = Post.find(params[:id])
end
def edit
#post = Post.find(params[:id])
end
def update
#post = Post.find(params[:id])
if #post.update(params[:post].permit(:title, :text))
redirect_to #post
else
render 'edit'
end
end
def destroy
#post = Post.find(params[:id])
#post.destroy
redirect_to posts_path
end
def create
#post = Post.new(post_params)
# it will also works #post=Post.new(params[:post].permit(:title,:text))
if #post.save
redirect_to #post
# or this command also works redirect_to action: :show, id: #post.id
else
render 'new'
end
end
def index
#posts = Post.all
end
private
def post_params
params.require(:post).permit(:title, :text)
end
end
comments_controller.rb
class CommentsController < ApplicationController
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create(params[:comment].permit(:commenter, :body))
redirect_to post_path(#post)
end
end
my routes.rb file is
Blog::Application.routes.draw do
resources :posts do
resources :comments
end
I have two migration files
create_posts.rb
class CreatePosts < ActiveRecord::Migration
def change
create_table :posts do |t|
t.string :title
t.text :text
t.timestamps
end
end
end
create_comments.rb
class CreateComments < ActiveRecord::Migration
def change
create_table :comments do |t|
t.string :commenter
t.text :body
t.references :post
#above line sets foreign key column for the association between the two models.
t.timestamps
end
#and bellow add_index line sets up an index for this association column.
add_index :comments, :post_id
end
end
my show.html.erb file is
<p>
<strong>Title:</strong>
<%= #post.title %>
</p>
<p>
<strong>Text:</strong>
<%= #post.text %>
</p>
<h2>Comments</h2>
<% #post.comments.each do |comment| %>
<p>
<strong>Commenter:</strong>
<%= comment.commenter %>
</p>
<p>
<strong>Comment:</strong>
<%= comment.body %>
</p>
<% end %>
<h2>Add a comment:</h2>
<%= form_for([#post, #post.comments.build]) do |f| %>
<p>
<%= f.label :commenter %><br />
<%= f.text_field :commenter %>
</p>
<p>
<%= f.label :body %><br />
<%= f.text_area :body %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
<%= link_to 'Edit Post', edit_post_path(#post) %> |
<%= link_to 'Back to Posts', posts_path %>
I used associations in the models whenever I am applying associations I am getting problem ,I am new to ruby as well as rails.I am using Rails4,Eclipse,Windows Xp(sp3) and mysql5.6 ,I am getting the above error when I want clicked the show link the error is I used associations in the models whenever I am applying associations I am getting problem ,I am new to ruby as well as rails.I am using Rails4,Eclipse,Windows Xp(sp3) and mysql5.6 ,I am getting the above error when I want clicked the show link the error is
I have a feeling you missed the part about nested resources. As in:
resources :posts do
resources :comments
end
This means the routes generated by resources :comments are nested within your posts, which results in URLs like this:
/posts/1/comments

trying to render a view on my reviews index page

I am a newbie to rails, and I've been pulling out my hair trying to figure out how to render my "logs" on my "reviews" page (which is now the index page).
I keep on getting a nomethoderror even when I've defined logs in my review controller.
Reviews controller
ReviewsController < ApplicationController
def index
#reviews = Review.all.order('created_at DESC').paginate(:page => params[:page], :per_page => 2)
end
def show
#logs = #logs.all
end
def new
#review = current_user.reviews.build
end
def edit
end
def create
#review = current_user.reviews.build(review_params)
if #review.save
redirect_to #review, notice: 'review was successfully created.'
else
render action: 'new'
end
end
def update
if #review.update(review_params)
redirect_to #review, notice: 'Review was successfully updated.'
else
render action: 'edit'
end
end
def destroy
#review.destroy
redirect_to reviews_url
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_review
#review = Review.find(params[:id])
end
def correct_user
#review = current_user.reviews.find_by(id: params[:id])
redirect_to reviews_path, notice: "Not authorized to edit this review!" if #review.nil?
end
# Never trust parameters from the scary internet, only allow the white list through.
def review_params
params.require(:review,).permit(:description, :attachment)
end
my reviews/index.html/erb
<div id='reviews' class='transitions-enabled'>
<% #reviews.each do |review| %>
<div class='box panel panel-default'>
<div class='panel-body'>
<p><%= review.description %></p>
<p><strong><%= review.user.name if review.user %></strong></p>
<%= link_to Time.now.strftime("%m/%d/%Y"), review %>
<% if review.user == current_user %>
<div class='actions'>
<%= link_to edit_review_path(review) do %>
<span class="glyphicon glyphicon-edit"></span> Edit
<% end %>
<%= link_to review, method: :delete, data: { confirm: 'Are you sure?' } do %>
<span class="glyphicon glyphicon-trash"></span>Delete
<% end %>
</div>
<% end %>
</div>
</div>
<% end %>
</div>
<%= render template:"logs/show" %>
<%= link_to new_review_path do %>
<span class="glyphicon glyphicon-pencil"></span>New Review
<% end %>
When you render the logs/show template in your "index" controller action, it doesn't go through the "show" action, it just renders the show view. So in order for the logs/show template to show your logs, you also need to initialize your #logs variable in the controller, like this:
def index
#reviews = Review.all.order('created_at DESC').paginate(:page => params[:page], :per_page => 2)
#logs = #logs.all
end
That way, when the logs/show view template is called, it has a #logs array to work from.

Ruby on Rails Getting name can't be blank error when trying to add new user

I am a Ruby on Rails newbie, and am trying to put into practice some of the tutorials I have been following.
I am currently trying to get a basic user signup working.
When the signup form is completed and submitted, the Firstname and Lastname fields are blanked out and I get two error messages (I also get a failing error when running the cucumber tests):
Firstname can't be blank
Lastname can't be blank
I think I have missed something fairly obvious with the authentication code, but can't spot what I have missed.
All my code is on my github account
Controller
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
# GET /users
# GET /users.json
def index
#users = User.all
end
# GET /users/1
# GET /users/1.json
def show
end
# GET /users/new
def new
#user = User.new
end
# GET /users/1/edit
def edit
end
# POST /users
# POST /users.json
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render action: 'show', status: :created, location: #user }
else
format.html { render action: 'new' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:firstname, :middlename, :lastname, :email, :password, :password_confirmation)
end
end
Model
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :firstname, :lastname, :middlename
validates :firstname, :presence =>true
validates :lastname, :presence=>true
validates :email, :presence=>true, :uniqueness => { :case_sensitive => false }
before_validation :downcase_email
def name
[firstname, middlename, lastname].compact.join(' ')
end
private
def downcase_email
self.email = self.email.downcase if self.email.present?
end
end
Views User
new.erb.rb
<h1>New user</h1>
<%= render 'form' %>
<%= link_to 'Back', users_path %>
_form.rb
<%= form_for(#user) do |f| %>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :firstname %><br />
<%= f.text_field :firstname %>
</div>
<div class="field">
<%= f.label :lastname %><br />
<%= f.text_field :lastname %>
</div>
<div class="field">
<%= f.label :middlename %><br />
<%= f.text_field :middlename %>
</div>
<div class="field">
<%= f.label :email %><br />
<%= f.text_field :email %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Since it looks like you're using devise, you can try running rails generate devise:views. This will generate all of the correct views for everything devise does. You might want to save the forms that you already have in case Devise tries to override them, though.