Rails 4 Associations: undefined method - ruby-on-rails-4

I've been looking all over the web for an answer to this for the past three hours so I'm going to post a question. I'm trying to create some basic forum software but I am having trouble with my relationships. This is the error I get
undefined method `forums' for # <ActiveRecord::Relation::ActiveRecord_Relation_Category:0x3706cb0>
my categories/index file
<% for category in #category %>
<div class="panel panel-success">
<div class="panel-heading">
<h3 class="panel-title"><%= link_to category.name, category_path(category.id) %></h3>
<h4><%= category.description %> </h4>
</div>
<% for forum in #category.forums %>
<div class="panel-body">
<h4><span class="glyphicon glyphicon-tree-conifer"></span><%= link_to forum.name, forum_path(forum.id) %> </h4>
</div>
<hr />
<% end %>
</div>
<% end %>
Categories Controller
class CategoriesController < ApplicationController
def index
#category = Category.all
end
def show
#category = Category.find(params[:id])
end
end
forums controller
class ForumsController < ApplicationController
def show
#forum = Forum.find(params[:id])
end
end
category model
class Category < ActiveRecord::Base
has_many :forums, dependent: :destroy
end
forum model
class Forum < ActiveRecord::Base
belongs_to :category
has_many :threads, dependent: :destroy
end
and my routes
ForumName::Application.routes.draw do
root 'static_pages#home'
resources :users
resources :sessions, only: [:new, :create, :destroy]
resources :categories, :path => "forum"
resources :forums
resources :topics
resources :posts
match '/signup', to: 'users#new', via: 'get'
match '/signin', to: 'sessions#new', via: 'get'
match '/signout', to: 'sessions#destroy', via: 'delete'
end
Hopefully I've provided enough info if anything else is required I'll update the post. Usually I can work these things out using google but this really has me stumped.Thanks in advance.

Issue in action CategoriesController#index
Should be changed to
#categories = Category.all
because Category.all expects to get several categories, not one
Also you should change categories/index file
<% for category in #categories %>
<div class="panel panel-success">
<div class="panel-heading">
<h3 class="panel-title"><%= link_to category.name, category_path(category.id) %></h3>
<h4><%= category.description %> </h4>
</div>
<% for forum in category.forums %>
<div class="panel-body">
<h4><span class="glyphicon glyphicon-tree-conifer"></span><%= link_to forum.name, forum_path(forum.id) %> </h4>
</div>
<hr />
<% end %>
</div>
<% end %>

Related

How to render another models form on another page?

Ok so Ive looked around at many answers posted on stackoverflow and many other sites because I know that this is a commonly asked question but I just cant seem to get it and would really appreciate it if someone could point me in the right direction. What Im trying to achieve here is really simple, Im trying to render a new form from another model, Post into my homepage, which is another controller that I created. So basically in my homepage it shows a list of all the recent Post that were created by users. Furthermore I wanted to user to be able to directly add a new Post from the homepage. Right now I have it displaying however clicking on the submit button does absolutely nothing.
Here is the form for POST
<div class="panel panel-primary">
<div class="container">
<div class="panel-heading">
<%= image_tag #post.user.avatar.url(:post_pic), class:"img-thumbnail" %>
<%= #post.user.name %>
<%= form_for(#post) do |f| %>
<% if #post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#post.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #post.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :content %><br>
<%= f.text_area :content %>
</div>
<div class="field">
<%= f.file_field :avatar %>
</div>
</div>
</div>
<div class="panel-footer">
<div class="actions">
<%= f.submit %>
</div>
</div>
<% end %>
</div>
Here is my homepage controller
class HomeController < ApplicationController
def index
if user_signed_in?
#posts = Post.all
#post = current_user.posts.build
else
redirect_to new_user_registration_path
end
end
def create
#post = current_user.posts.build(post_params)
#post.save
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:user_id, :content, :avatar)
end
end
Lastly my homepage index
<div class="row">
<div class="col-md-3"></div>
<div class="col-md-5">
<h1>Home#index</h1>
<p>Find me in app/views/home/index.html.erb</p>
<%= render 'posts/form' %>
<% #posts.each do |post|%>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
<%= image_tag post.user.avatar.url(:post_pic), class:"img-thumbnail" %>
<%= post.user.name %>
</h3>
</div>
<div class="panel-body">
<%= post.content %></br></br>
<% if post.avatar.file? %>
<%= image_tag post.avatar.url(:test), class:"img-thumbnail" %></br>
<% end %>
</div>
</div>
<% end %>
</div>
</div>
Routes
Rails.application.routes.draw do
resources :posts
get 'users/index'
get 'users/show'
root 'home#index'
devise_for :users
So, you're doing like saving post data using another Controller(Home) instead of Post Controller, right?
Your partial form for post uses:
<%= form_for(#post) do |f| %>
// #post generated url (/posts)
// will look for create method in POST Controller
I suggest to put your saving codes in proper controller(posts), so you will prevent code duplication/redundancy.
TIP:
If you are worrying about redirection from Home view or from Posts view,
you can use params[:controller] for checking where the request came from, by just using if statement.
Finally, you can redirect it to proper page after saving.

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.

Creating variable for association in ruby on rails controller

I have a set up where Goals have Steps and Steps have Tasks. In my view I am showing a goal, if that goal has steps then I can pull those and show them as well. I am having a hard time showing the tasks for each individual step now. I can get the task associated with the proper step so part of this is working, but I cannot access any of the data, name and description specifically for the task.
I am just unsure how to create this in the controller. I have cruised around the guide trying to find a solution and tried things like
#goal.steps.tasks
#step.tasks
I just cannot find anything that clicks for creating the variable in the controller so I can access it.
goals_controller.rb show method
def show
#goal = Goal.find(params[:id])
#steps = #goal.steps(page: params[:page])
# #tasks = ?
end
goal.rb
class Goal < ActiveRecord::Base
has_many :steps, dependent: :destroy
has_many :tasks, through: :steps
end
step.rb
class Step < ActiveRecord::Base
belongs_to :goals
has_many :tasks, dependent: :destroy
default_scope -> { order(created_at: :desc) }
end
task.rb
class Task < ActiveRecord::Base
belongs_to :steps
end
views
goals/show view
<p>
<% if #goal.steps.any? %>
<!-- Projects Row -->
<div class="row">
<%= render #steps %>
</div>
<!-- /.row -->
<% else %>
No steps for this goal.
<% end %>
</p>
the partial rendered for the steps
<div id="steps-<%= step.id %>" class="col-md-3 portfolio-item not completed" style="background-color:#e26a5c;border-radius:10px;border:1px solid #6cbdc4;margin:0 5px 5px 0;">
<h3>
<p>In order to achieve this goal I need to <strong><%= step.name %></strong> in <strong><%= time_ago_in_words(step.deadline) %></strong></p>
</h3>
<img src="/img/icon-edit.png">
<% if step.tasks.any? %>
<%= render "tasks/task" %>
<% else %>
<%end %>
</div>
<% else %>
<div id="steps-<%= step.id %>" class="col-md-3 portfolio-item completed" style="background-color:#6cbdc4;border-radius:10px;border:1px solid #e26a5c;margin:0 5px 5px 0;">
<h3>
<p>In an effort to achieve this goal I needed to <strong><%= step.name %></strong> in <strong><%= time_ago_in_words(step.deadline) %></strong></p>
</h3>
<img src="/img/icon-edit.png">
</div>
Tasks/task is the partial I am trying to pull in, I can link to it on the correct step and everything, but it says undefined method when I put task.name or task.description in.
Try this in your goals_controller.rb:
def show
#goal = Goal.find(params[:id])
#steps = #goal.steps(page: params[:page]).includes(:tasks)
end
Then in your view you could have something like this:
<ul>
<% #steps.each do |step| %>
<li>
<%= step %>
<p>Tasks:</p>
<ul>
<% step.tasks.each do |task| %>
<li><%= task %></li>
<% end %>
</ul>
</li>
<% end %>
</ul>
For more info on includes: http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations

render multiple objects to a users profile page

I am trying to show the 'status' & 'project' from an '#user' on that users profile page, I believe I have the correct relationships etc but the error I am getting is that I cannot call render multiple times in one action.
class ProfilesController < ApplicationController
def show
#user = User.find_by_profile_name(params[:id])
if #user
#statuses = #user.statuses.all
render actions: :show
else
render file: 'public/404', status: 404, formats: [:html]
end
#user = User.find_by_profile_name(params[:id])
if #user
#projects = #user.projects.all
render actions: :show
else
render file: 'public/404', status: 404, formats: [:html]
end
end
end
What is the best way to express the above, to render both items on the users profile page without calling render twice?
This is my view:
<div class="container">
<div class="page-header">
<h1><%= "Hi " + #user.first_name + "!" %>
</div>
<div class="col-md-6 col-md-offset-3">
<%= link_to "Create Project", new_project_path, class: "btn btn-success btn-block" %>
</div>
<% if #statuses %>
<% #statuses.each do |status| %>
<div class="well">
<%= status.content %>
<hr />
<%= link_to time_ago_in_words(status.created_at), status_path(status) %> ago
</div>
<% end %>
<% end %>
<% if #projects %>
<% #projects.each do |project| %>
<div class="well">
<%= project.title %>
<hr />
<%= link_to time_ago_in_words(project.created_at), projects_path(project) %> ago
</div>
<% end %>
<% end %>
</div>
Thanks for your time!
Try as below.
class ProfilesController < ApplicationController
def show
#user = User.find_by_profile_name(params[:id])
if #user
#statuses = #user.statuses.all
#projects = #user.projects.all
render action: :show
else
render file: 'public/404', status: 404, formats: [:html]
end
end
end

Rails 4.0 & Cocoon: nested fields under fields_for don't appear in Edit

Hoping someone can suggest a fix here. I am fairly new to Rails, and exploring the changes in Rails 4.0. I built this simple recipe book app in Rails 4.0. I have a main model for recipes (name, cook_time, oven_temp, instructions, etc.). Because some recipes may have 5 ingredients and others may have 20, I wanted to break ingredients out in a separate model with a has_many association. So Recipes has_many Ingredients and accepts_nested_attributes_for :ingredients. Here are the models:
recipe.rb
class Recipe < ActiveRecord::Base
belongs_to :user
belongs_to :category
has_many :ingredients, :dependent => :destroy
validates :name, presence: true, length: { maximum: 50 }
accepts_nested_attributes_for :ingredients,
:reject_if => lambda { |a| a[:name].blank? },
:allow_destroy => true
end
ingredient.rb
class Ingredient < ActiveRecord::Base
belongs_to :recipe
end
Reminder: Rails 4.0 no longer uses attr_accessible, but moves assignment into the controller with strong params.
recipes_controller.rb
class RecipesController < ApplicationController
before_action :find_recipe, only: [:show, :edit, :update, :destroy]
before_action :set_current_user, except: [:index, :show]
respond_to :html, :js
...
def edit
end
def update
if #recipe.update_attributes(recipe_params)
redirect_to #recipe
else
render :edit
end
end
...
def find_recipe
#recipe = Recipe.find(params[:id])
end
private
def recipe_params
params.require(:recipe).permit( :id, :name, :category_id, :cook_time, :oven_temp, :calories, :instructions, :notes, :email, ingredients_attributes: [:id, :name])
end
end
I'm using the excellent Cocoon gem from nathanvda to manage nested form fields dynamically, and it works great in 'recipes#new', and saves the information correctly. However, the ingredients fields do not appear in the 'recipes#edit' view! Here is the code for my 'form' and ingredients_fields partials.
_form.html.erb (abbreviated)
<%= form_for #recipe, html: { class: 'form-horizontal' } do |f| %>
<fieldset>
<legend>Main Information</legend>
<div class="field form-group">
<%= f.label :name, "Recipe name", class: "col-lg-2 control-label" %>
<div class="col-lg-5">
<%= f.text_field :name, class: "form-control" %>
</div>
</div>
<div class="field form-group">
<%= f.label :cook_time, class: "col-lg-2 control-label" %>
<div class="col-lg-5">
<%= f.text_field :cook_time, class: "form-control" %>
</div>
</div>
...
</fieldset>
<legend>Ingredients</legend>
<p>Number of ingredients: <%= f.object.ingredients.count unless f.object.ingredients.nil? %></p>
<fieldset id="ingredients">
<% f.fields_for :ingredients do |builder| %>
<%= render 'ingredient_fields', :f => builder %>
<% end %>
<p class="links">
<%= link_to_add_association 'add ingredient', f, :ingredients, { class:"btn btn-primary" } %>
</p>
</fieldset>
<fieldset>
<legend>How to make it</legend>
<div class="field form-group">
<%= f.label :instructions, class: "col-lg-2 control-label" %>
<div class="col-lg-5">
<%= f.text_area :instructions, class: "form-control", rows: "7" %>
</div>
</div>
...
</div>
</fieldset>
<% end %>
_ingredients_fields.html.erb
<div class="nested-fields">
<div class="form-group">
<%= f.label :name, "Ingredient", class: "col-lg-2 control-label" %>
<div class="col-lg-5">
<%= f.text_field :name, class: "form-control" %>
</div>
<%= link_to_remove_association "remove", f %>
</div>
</div>
As I said, pretty simple, removed all error checking and messaging, just the basics. Any ideas about what I am missing? I know there are ingredients in the recipe as I load edit from a show view. Thanks in advance for any advice!
Kevin
Ack. it was as simple as an '=' sign - must have looked at the <% f.fields_for... %> a thousand times and just didn't notice I'd missed adding the <%=.
<%= f.fields_for :ingredients do |builder| %>