Error validations from child model Ruby on Rails - ruby-on-rails

I got a problem which I can't solve. I made two models; one model called Film is the parent model and another model called Review is the child model. I got validation conditions on the child model but it does not display on the view.
Film model
class Film < ApplicationRecord
has_many :reviews
validates_presence_of :filmtitle, presence: true
validates_presence_of :filmdescription, presence: true
validates_presence_of :filmdirector, presence: true
validates_presence_of :filmrating, presence: true
validates_presence_of :filmstarname, presence: true
end
Review model
class Review < ApplicationRecord
validates :rating, presence: true
validates :commenter, presence: true
validates :body, presence: true
belongs_to :film
end
Review Controller
class ReviewsController < ApplicationController
def create
#film = Film.find(params[:film_id])
#review = #film.reviews.create(review_params)
redirect_to film_path(#film)
end
private
def review_params
params.require(:review).permit(:commenter, :body, :rating)
end
end
Film show.html.erb
<% if #film.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#film.errors.count, "error") %></h2>
<ul>
<% #film.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= form_for([#film, Review.new]) do |f| %>
<p>
<%= f.label :commenter %><br>
<%= f.text_field :commenter, :placeholder => 'Your name' %>
</p>
<p>
<%= f.label :body %><br>
<%= f.text_area :body, :placeholder => 'Your comment' %>
</p>
<p>
<%= f.label :rating %><br>
<%= f.select :rating, ['1 Star', '2 Stars', '3 Stars', '4 Stars', '5 Stars'] %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
Film Controller
class FilmsController < ApplicationController
before_action :set_film, only: [:show]
# GET /films
# GET /films.json
def index
#films = Film.all.paginate(page: params[:page], per_page: 30)
#reviews = Review.new
end
# GET /films/1
# GET /films/1.json
def show
end
# GET /films/new
def new
end
# GET /films/1/edit
def edit
end
# POST /films
# POST /films.json
def create
end
# PATCH/PUT /films/1
# PATCH/PUT /films/1.json
def update
end
# DELETE /films/1
# DELETE /films/1.json
def destroy
end
private
# Use callbacks to share common setup or constraints between actions.
def set_film
#film = Film.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def film_params
params.require(:film).permit(:filmtitle, :filmdescription)
end
end
route.rb
Rails.application.routes.draw do
resources :films do
resources :reviews
end
resources :rentals
resources :buys
resources :admin
resources :adminrentals
resources :adminfilms
resources :logins
resources :admins_login
resources :games
get '/adminCool' => 'admins_login#index'
get '/adminlogin' => 'admins_sessions#new'
post '/adminlogin' => 'admins_sessions#create'
get '/adminlogout' => 'admins_sessions#destroy'
get '/adminsignup' => 'admins#new'
post '/admins' => 'admins#create'
get '/login' => 'sessions#new'
post '/login' => 'sessions#create'
get '/logout' => 'sessions#destroy'
get '/signup' => 'users#new'
post '/users' => 'users#create'
get '/cool' => 'logins#index'
end

Please try
def create
#film = Film.find(params[:film_id])
#review = #film.reviews.new(review_params)
if #review.save
redirect_to film_path(#film)
else
render "films/#{#film.id}"
end
end

Related

simple_form association doesn't save belongs_to id

I have a recipient and category model. It's a simple association of 1 category has many recipients. When I try to update the recipient form and assign a category, it won't save to the record. If I use the console and update a record manually, e.g. Recipient.update(9, category_id: 13), I see the correct category assigned to the recipient but when I try to edit/update the record, it won't save to the new chosen category.
Here is my recipient model
class Recipient < ActiveRecord::Base
belongs_to :category
accepts_nested_attributes_for :category
end
Here is my category model
class Category < ActiveRecord::Base
has_many :recipients
validates :category, presence: true
default_scope { order('category')}
end
here is the recipient controller
class RecipientsController < ApplicationController
def index
#recipients = Recipient.order(:recipient_name).page(params[:page])
end
def new
#recipient = Recipient.new
end
def show
#recipient = Recipient.find(params[:id])
end
def create
#recipient = Recipient.new(recipient_params)
if #recipient.save
redirect_to recipients_path
else
render :new
end
end
def edit
#recipient = Recipient.find(params[:id])
end
def update
#recipient = Recipient.find(params[:id])
recipient_params = params.require(:recipient).permit(:recipient_name, :alternate_name, :description, :city, :state, :country, category_attributes: [:category, :id])
#recipient.update_attributes(recipient_params)
redirect_to recipient_path(id: #recipient.id)
end
def destroy
#recipient = Recipient.find(params[:id])
#recipient.destroy
redirect_to recipients_path
end
private
def recipient_params
params.require(:recipient).permit(:recipient_name, :alternate_name, :description, :city, :state, :country, product_attributes: [:product_name, recipient_products: [:recipient_id, :product_id]], channel_attributes: [:channel_name, recipient_channels: [:recipient_id, :channel_id]], category_attributes: [:id, :category])
end
end
here is the edit view
<div class="row">
<div class="col-sm-6">
<h2>Edit <%= #recipient.recipient_name %></h2>
<%= simple_form_for #recipient do |form| %>
<%= form.error_notification %>
<%= form.input :recipient_name, placeholder: 'Recipient', label: 'Recipient Name' %>
<%= form.input :alternate_name, placeholder: 'Alternate Name' %>
<%= form.association :category, label_method: :category, value_method: :id %>
<%= form.input :description, placeholder: 'Description'%>
<%= form.input :city, placeholder: 'City'%>
<%= form.input :state, placeholder: 'State' %>
<%= form.input :country, as: :country, priority: ['US', 'CA'] %>
<%= form.button :submit, 'Update Recipient', {:class=>"btn btn-secondary"} %>
<%= link_to "Cancel", :back, {:class=>"btn btn-default"} %>
<% end %>
</div>
</div>
and here is my routes.rb file
Rails.application.routes.draw do
root to: 'home#index'
resources :media_points
resources :products
resources :channels
resources :recipients
resources :media_point_products
resources :distributions
resources :categories do
resources :recipients
end
get '/listing' => "listing#index"
devise_for :admins
devise_for :users
resources :users
end
I wrote it as an answer since the format is a pain in comments:
Change your recipient_params private method from:
category_attributes: [:category, :id]
to
category_id: param_that_has_category_id_here
Also, you have two routes for recipients and it is going to utilize the first matching route which is not the nested recipients in categories route you have further down. If the first change in your private method didn't fix it I would specify the nested situation in simpleform doing as follows since you are probably looking to use the nested route:
simple_form_for [#category, #recipient], url: 'nested_route_path_here' do |f|
Just add #category = Category.new to your new action in the recipients controller and then in your create action you'll have the category param sent via params[:category_id]

Ruby on rails. Form for a nested model in a different view

I've been battling this for a while now and I can't figure it out. I have a user model using devise. Users can upload songs, and add youtube videos etc..
I'm trying to let users add/delete songs and videos from the devise edit registrations view.
Videos upload fine, but as songs are a nested resource of playlists, which belongs to user, I think I'm getting muddle up.
Music uploads with the same form on it's corresponding page, but not from the devise registration edit view.
routes:
devise_for :users, controllers: { registrations: "users/registrations", sessions: "users/sessions" }
resources :videos
resources :playlists do
resources :songs
end
Devise registrations controller:
def edit
#song = Song.new
#video = Video.new
end
Form in devise edit registrations:
<div id="user-music-box">
<p class="p-details-title"> Upload Music </p>
<%= simple_form_for [#user.playlist, #song] do |f| %>
<%= f.file_field :audio %>
<%= f.button :submit %>
<% end %>
</div>
<div id="user-video-box">
<p class="p-details-title"> Add videos </p>
<%= simple_form_for #video do |f| %>
<%= f.input :youtubeurl %>
<%= f.button :submit %>
<% end %>
</div>
As I said, videos (Which is a youtube url string) create and save no problem. The exact same form for songs, basically seems to just update the user registration. The song information is shown in the server logs, but no playlist_id is present and nothing gets saved.
Songs controller:
def new
if user_signed_in?
#song = Song.new
if current_user.playlist.songs.count >= 5
redirect_to user_path(current_user)
flash[:danger] = "You can only upload 5 songs."
end
else
redirect_to(root_url)
flash[:danger] = "You must sign in to upload songs"
end
end
def create
#song = current_user.playlist.songs.new song_params
#song.playlist_id = #playlist.id
if #song.save
respond_to do |format|
format.html {redirect_to user_path(current_user)}
format.js
end
else
render 'new'
end
end
Playlist.rb
class Playlist < ActiveRecord::Base
belongs_to :user
has_many :songs, :dependent => :destroy
accepts_nested_attributes_for :songs
end
song.rb
class Song < ActiveRecord::Base
belongs_to :user
belongs_to :playlist
has_attached_file :audio
validates_attachment_presence :audio
validates_attachment_content_type :audio, :content_type => ['audio/mp3','audio/mpeg']
end
Unless you're passing songs/playlists through accepts_nested_attributes_for you shouldn't be using registrations#edit. I'll detail both ways to achieve what you want below:
Nested Attributes
#app/models/user.rb
class User < ActiveRecord::Base
has_many :videos
has_many :playlists
has_many :songs, through: :playlists
accepts_nested_attributes_for :videos
end
#app/models/playlist.rb
class PlayList < ActiveRecord::Base
belongs_to :user
has_and_belongs_to_many :songs
end
#app/models/song.rb
class Song < ActiveRecord::Base
has_and_belongs_to_many :playlists
end
The importance of this is that to use it properly, you're able to edit the #user object directly, passing the nested attributes through the fields_for helper:
#config/routes.rb
devise_for :users, controllers: { registrations: "users/registrations", sessions: "users/sessions" }
#app/controllers/users/registrations_controller.rb
class Users::RegistrationsController < ApplicationController
before_action :authenticate_user!, only: [:edit, :update]
def edit
#user = current_user
#user.playlists.build.build_song
#user.videos.build
end
def update
#user = current_user.update user_params
end
private
def user_params
params.require(:user).permit(:user, :attributes, videos_attributes: [:youtubeurl], playlists_attributes: [song_ids: [], song_attributes: [:title, :artist, :etc]])
end
end
This will allow you to use:
#app/views/users/registrations/edit.html.erb
<%= form_for #user do |f| %>
<%= f.fields_for :videos do |v| %>
<%= v.text_field :youtubeurl %>
<% end %>
<%= f.fields_for :playlists do |p| %>
<%= p.collection_select :song_ids, Song.all, :id, :name %>
<%= p.fields_for :song do |s| %>
<%= f.text_field :title %>
<% end %>
<% end %>
<%= f.submit %>
<% end %>
This will give you a single form, from which you'll be able to create videos, playlists and songs for the #user.
Separate
The other option is to create the object separately.
There is no technical reason for preferring this way over nested attributes; you'd do it to make sure you have the routes in the correct order etc.
As a note, you need to remember that routes != model structure. You can have any routes you want, so long as they define a good pattern for your models:
# config/routes.rb
authenticated :user do #-> user has to be logged in
resources :videos, :playlists, :songs #-> url.com/videos/new
end
# app/controllers/videos_controller.rb
class VideosController < ApplicationController
def new
#video = current_user.videos.new
end
def create
#video = current_user.videos.new video_params
#video.save
end
private
def video_params
params.require(:video).permit(:youtubeurl)
end
end
# app/views/videos/new.html.erb
<%= form_for #video do |f| %>
<%= f.text_field :youtubeurl %>
<%= f.submit %>
<% end %>
The above will require the duplication of the VideosController for Playlists and Songs

Rails Tutorial: undefined method for nil:NilClass

I successfully finished the Rails Tutorial by Michael Hartl where you are building an app like twitter. Now I want to add some other things and got stuck trying to add a like-function to the microposts.
As a basis for this I took the relationships between followers.
So a user has_many (microposts) 'liked' and a micropost has_many 'likers' (users).
I keep getting the error
ActionView::Template::Error: undefined method 'likers' for nil:NilClass
in the Microposts Interface Test and in the Users Profile Test.
Here's my code:
routes.rb:
Rails.application.routes.draw do
root 'static_pages#home'
get 'help' => 'static_pages#help'
get 'about' => 'static_pages#about'
get 'contact' => 'static_pages#contact'
get 'signup' => 'users#new'
get 'login' => 'sessions#new'
post 'login' => 'sessions#create'
delete 'logout' => 'sessions#destroy'
resources :users do
member do
get :following, :followers, :liked
end
end
resources :microposts do
member do
get :likers
end
end
resources :account_activations, only: [:edit]
resources :password_resets, only: [:new, :create, :edit, :update]
resources :microposts, only: [:create, :destroy]
resources :relationships, only: [:create, :destroy]
end
app/models/like.rb:
class Like < ActiveRecord::Base
belongs_to :liker, class_name: "User"
belongs_to :micropost, class_name: "Micropost"
validates :liker_id, presence: true
validates :micropost_id, presence: true
end
app/models/micropost.rb:
class Micropost < ActiveRecord::Base
belongs_to :user
has_many :passive_likes, class_name: "Like",
foreign_key: "micropost_id",
dependent: :destroy
has_many :likers, through: :passive_likes, source: :micropost
default_scope -> { order(created_at: :desc) }
mount_uploader :picture, PictureUploader
validates :user_id, presence: true
validates :content, presence: true, length: { maximum: 140 }
validate :picture_size
private
# Validates the size of an uploaded picture.
def picture_size
if picture.size > 5.megabytes
errors.add(:picture, "maximal 5MB")
end
end
end
app/models/user.rb:
class User < ActiveRecord::Base
has_many :microposts, dependent: :destroy
has_many :active_relationships, class_name: "Relationship",
foreign_key: "follower_id",
dependent: :destroy
has_many :passive_relationships, class_name: "Relationship",
foreign_key: "followed_id",
dependent: :destroy
has_many :active_likes, class_name: "Like",
foreign_key: "liker_id",
dependent: :destroy
has_many :liked, through: :active_likes, source: :micropost
has_many :following, through: :active_relationships, source: :followed
has_many :followers, through: :passive_relationships, source: :follower
mount_uploader :avatar, AvatarUploader
attr_accessor :remember_token, :activation_token, :reset_token
before_save :downcase_email
before_create :create_activation_digest
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
has_secure_password
validates :password, length: { minimum: 6 }, allow_blank: true
# Returns the hash digest of the given string.
def self.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
# Returns a random token.
def self.new_token
SecureRandom.urlsafe_base64
end
# Remembers a user in the database for use in persistent sessions.
def remember
self.remember_token = User.new_token
update_attribute(:remember_digest, User.digest(remember_token))
end
# Returns true if the given token matches the digest.
def authenticated?(attribute, token)
digest = send("#{attribute}_digest")
return false if digest.nil?
BCrypt::Password.new(digest).is_password?(token)
end
# Forgets a user.
def forget
update_attribute(:remember_digest, nil)
end
# Activates an account.
def activate
update_attribute(:activated, true)
update_attribute(:activated_at, Time.zone.now)
end
# Sends activation email.
def send_activation_email
UserMailer.account_activation(self).deliver_now
end
# Sets the password reset attributes.
def create_reset_digest
self.reset_token = User.new_token
update_attribute(:reset_digest, User.digest(reset_token))
update_attribute(:reset_sent_at, Time.zone.now)
end
# Sends password reset email.
def send_password_reset_email
UserMailer.password_reset(self).deliver_now
end
# Returns true if a password reset has expired.
def password_reset_expired?
reset_sent_at < 2.hours.ago
end
# Defines a proto-feed.
# See "Following users" for the full implementation.
# Returns a user's status feed.
def feed
following_ids = "SELECT followed_id FROM relationships
WHERE follower_id = :user_id"
Micropost.where("user_id IN (#{following_ids})
OR user_id = :user_id", user_id: id)
end
# Follows a user.
def follow(other_user)
active_relationships.create(followed_id: other_user.id)
end
# Unfollows a user.
def unfollow(other_user)
active_relationships.find_by(followed_id: other_user.id).destroy
end
# Returns true if the current user is following the other user.
def following?(other_user)
following.include?(other_user)
end
# Likes a micropost
def like(any_post)
active_like.create(micropost_id: any_post.id)
end
# Unlikes a micropost
def unlike(any_post)
active_like.find_by(micropost_id: any_post.id).destroy
end
# Returns true if the current user is liking the micropost
def liked?(any_post)
liked.include?(any_post)
end
private
# Converts email to all lower-case.
def downcase_email
self.email = email.downcase
end
# Creates and assigns the activation token and digest.
def create_activation_digest
self.activation_token = User.new_token
self.activation_digest = User.digest(activation_token)
end
end
app/views/users/show.html.erb:
<% provide(:title, #user.name) %>
<div class="row">
<aside class="col-md-4">
<section>
<h1>
<%= gravatar_for #user %>
<%= #user.name %>
</h1>
</section>
<section class="stats">
<%= render 'shared/stats' %>
</section>
</aside>
<div class="col-md-8">
<%= render 'follow_form' if logged_in? %>
<% if #user.microposts.any? %>
<h3>Posts (<%= #user.microposts.count %>)</h3>
<ol class="microposts">
<%= render #microposts %>
</ol>
<%= will_paginate #microposts %>
<% end %>
</div>
</div>
app/views/microposts/_micropost.html.erb:
<li id="micropost-<%= micropost.id %>">
<%= link_to gravatar_for(micropost.user, size: 50), micropost.user %>
<span class="user"><%= link_to micropost.user.name, micropost.user %></span>
<span class="content">
<%= micropost.content %>
<%= image_tag micropost.picture.url if micropost.picture? %>
</span>
<span class="timestamp">
Posted <%= time_ago_in_words(micropost.created_at) %> ago.
<%= render 'shared/morestats' %>
<%= render 'microposts/like_form' if logged_in? %>
<% if current_user?(micropost.user) %>
<%= link_to "löschen", micropost, method: :delete,
data: { confirm: "Diesen Post wirklich löschen?" } %>
<% end %>
</span>
</li>
app/views/microposts/_like_form.html.erb:
<% unless current_user?(#user) %>
<div id="like_form">
<% if #micropost.liked?(#user) %>
<%= render 'unlike' %>
<% else %>
<%= render 'like' %>
<% end %>
</div>
<% end %>
app/views/microposts/_like.html.erb:
<%= form_for(current_user.active_likes.build) do |f| %>
<div><%= hidden_field_tag :micropost_id, #user.id %></div>
<%= f.submit "Like", class: "btn btn-primary" %>
<% end %>
app/views/microposts/_unlike.html.erb:
<%= form_for(current_user.active_likes.build) do |f| %>
<div><%= hidden_field_tag :micropost_id, #user.id %></div>
<%= f.submit "Like", class: "btn btn-primary" %>
<% end %>
If there's any code missing let me know. Thanks in advance!
Here's the full error:
ERROR["test_micropost_interface", MicropostsInterfaceTest, 4.72409967]
test_micropost_interface#MicropostsInterfaceTest (4.72s)
ActionView::Template::Error: ActionView::Template::Error: undefined method `likers' for nil:NilClass
app/views/shared/_morestats.html.erb:4:in `_app_views_shared__morestats_html_erb___939926434685355917_93681000'
app/views/microposts/_micropost.html.erb:10:in `_app_views_microposts__micropost_html_erb___1029196025817541101_93766560'
app/views/users/show.html.erb:19:in `_app_views_users_show_html_erb___2389533090581269630_85562520'
test/integration/microposts_interface_test.rb:33:in `block in <class:MicropostsInterfaceTest>'
app/views/shared/_morestats.html.erb:4:in `_app_views_shared__morestats_html_erb___939926434685355917_93681000'
app/views/microposts/_micropost.html.erb:10:in `_app_views_microposts__micropost_html_erb___1029196025817541101_93766560'
app/views/users/show.html.erb:19:in `_app_views_users_show_html_erb___2389533090581269630_85562520'
test/integration/microposts_interface_test.rb:33:in `block in <class:MicropostsInterfaceTest>'
code for test/integration/microposts_interface_test.rb:
require 'test_helper'
class MicropostsInterfaceTest < ActionDispatch::IntegrationTest
def setup
#user = users(:peter)
end
test "micropost interface" do
log_in_as(#user)
get root_path
assert_select 'div.pagination'
# Invalid submission
assert_no_difference 'Micropost.count' do
post microposts_path, micropost: { content: "" }
end
assert_select 'div#error_explanation'
# Valid submission
content = "This micropost really ties the room together"
assert_difference 'Micropost.count', 1 do
post microposts_path, micropost: { content: content }
end
assert_redirected_to root_url
follow_redirect!
assert_match content, response.body
# Delete a post.
assert_select 'a', text: 'löschen'
first_micropost = #user.microposts.paginate(page: 1).first
assert_difference 'Micropost.count', -1 do
delete micropost_path(first_micropost)
end
# Visit a different user.
get user_path(users(:archer))
assert_select 'a', text: 'löschen', count: 0
end
end
code for test/integration/users_profile_test.rb:
require 'test_helper'
class UsersProfileTest < ActionDispatch::IntegrationTest
include ApplicationHelper
def setup
#user = users(:peter)
end
test "profile display" do
get user_path(#user)
assert_template 'users/show'
assert_select 'title', full_title(#user.name)
assert_select 'h1', text: #user.name
assert_select 'h1>img.gravatar'
assert_match #user.microposts.count.to_s, response.body
assert_select 'div.pagination'
#user.microposts.paginate(page: 1).each do |micropost|
assert_match micropost.content, response.body
end
end
end
code for shared/_morestats.html.erb:
<% #micropost %>
<div class="morestats">
<strong id="likers" class="morestat">
<%= #micropost.likers.count %>
</strong>
likers
</div>
The issue is that you wrote #micropost referring to a variable visible to all the views (a #micropost object that you never assigned). If you write micropost without the #, you are referring to a local variable that was assigned with the :locals => { :micropost => micropost }.
In shared/morestats, line 4, you are doing #micropost.likers but if you pay attention, you are not passing any micropost to the partial (see micropost, line 10):
<%= render 'shared/morestats' %>
You have to change that to something like this:
<%= render :partial => 'shared/morestats', :locals => { :micropost => micropost } %>
And also remove the '#' from the micropost in the morestats. Just like this:
<% micropost %>
<div class="morestats">
<strong id="likers" class="morestat">
<%= micropost.likers.count %>
</strong>
likers
</div>
You have the same issue here:
<%= render 'microposts/like_form' %>
You have to change that to something like this:
<%= render :partial => 'microposts/like_form', :locals => { :micropost => micropost } %>
And like_form to this:
<% unless current_user?(#user) %>
<div id="like_form">
<% if #user.liked?(micropost) %>
<%= render 'unlike' %>
<% else %>
<%= render 'like' %>
<% end %>
</div>
<% end %>
Another solution, if you don't want to change the # you can just modify the _micropost partial like this:
<% #micropost = micropost %>
<%= render 'shared/morestats' %>
But this is less elegant than the previous solution.
<%= #book.likes.count %>
<% like = current_user.likes.find_by(book: #book) %>
<%# if like.nil? %>
<%= button_to "like", likes_path, params: {like: {book_id: #book.id }}, method: :post %>
<%# else %>
<%#= button_to "UnLike", like_path(like), method: :delete %>
<% #end %>
-->

Rails polymorphic posts associations and form_for in views

I've been having trouble setting up the form for a polymorphic "department" post in the department view. I followed the rails-cast tutorial for polymorphic associations here
Models:
class Course < ActiveRecord::Base
belongs_to :department, inverse_of: :courses
has_and_belongs_to_many :users, -> { uniq }
has_many :posts, as: :postable #allows polymorphic posts
end
class Department < ActiveRecord::Base
has_many :courses, inverse_of: :department
has_many :posts, as: :postable #allows polymorphic posts
has_and_belongs_to_many :users, -> {uniq}
end
class Post < ActiveRecord::Base
belongs_to :user, touch: true #updates the updated_at timestamp whenever post is saved
belongs_to :postable, polymorphic: true #http://guides.rubyonrails.org/association_basics.html#polymorphic-associations
belongs_to :department, counter_cache: true #for counting number of posts in department
belongs_to :course, counter_cache: true
validates :department_id, :course_id, presence: true
end
config/routes
devise_for :users
devise_scope :users do
match '/users/:id', to: "users#show", via: 'get'
end
resources :departments do
resources :courses
resources :posts
end
resources :courses do
resources :posts
end
views/departments/show.html.erb
<div class="tab-pane" id="posts"><br>
<center><h3>Posts:</h3></center>
<%= render "posts/form", postable: #department %>
</div>
views/posts/_form.html.erb
<%= render "posts/wysihtml5" %>
<center><h3>Create New Post:</h3></center>
<%= form_for [#postable, Post.new] do |f| %>
<%= f.label :title %>
<%= f.text_field :title, class: "form-control" %>
<%= f.label :description %>
<%= f.text_area :description, :rows => 3, class: "form-control" %>
<%= f.text_area :content, :rows => 5, placeholder: 'Enter Content Here', class: "wysihtml5" %>
<span class="pull-left"><%= f.submit "Create Post", class: "btn btn-medium btn-primary" %></span>
<% end %>
controllers/post_controller.rb
class PostsController < ApplicationController
before_filter :find_postable
load_and_authorize_resource
def new
#postable = find_postable
#post = #postable.posts.new
end
def create
#postable = find_postable
#post = #postable.posts.build(post_params)
if #post.save
flash[:success] = "#{#post.title} was sucessfully created!"
redirect_to department_post_path#id: nil #redirects back to the current index action
else
render action: 'new'
end
end
def show
#post = Post.find(params[:id])
end
def index
#postable = find_postable
#posts = #postable.posts
end
...
private
def post_params
params.require(:post).permit(:title, :description, :content)
end
def find_postable #gets the type of post to create
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
controllers/departments_controller.rb
def show
id = params[:id]
#department = Department.find(id)
#course = Course.new
#course.department_id = #department
end
The error is "undefined method `posts_path' for #<#:0x0000010d1dab10>"
I think the error has something to do with the path in the form, but I don't know what. I've tried [#postable, #postable.posts.build] as well but that just gives me undefined method: PostsController.
Anybody know what's going on and how I can fix it?
#department is passed into the form partial as a local variable, but the form calls an instance variable:
# views/departments/show.html.erb
<%= render "posts/form", postable: #department %> # <------ postable
# views/posts/_form.html.erb
<%= form_for [#postable, Post.new] do |f| %> # <------ #postable
Thus, the namespaced route is not properly determined
[#postable, Post.new] # => departments_posts_path
[ nil , Post.new] # => posts_path
Checking your routes, posts are only accessible via nested routes. posts_path is not a valid route, it's method does not exist, and the error is correct: undefined method `posts_path'
Fix:
Set a #postable instance variable in the departments controller so that the form helper can use it:
def show
id = params[:id]
#postable, #department = Department.find(id) # <-- add #postable
#course = Course.new
#course.department_id = #department
end
Then you can simply call render in the view:
<%= render "posts/form" %>

Rails Link_to is linking to undesired view

My link_to in my view is going to a completely different "show.html.erb" than I'd like it to. I'm basically trying to understand why the "link_to #exhibit is linking to an "Investigation" profile. I think it may have to do with my routes file or the fact that its a "belong to" relationship...but can't seem to get it workin...what should that link_to be?
UPDATE: (AS PER BROIS QUESTION)
The missing misbehaving link_to is in the <%= link_to #exhibit do %> in show.html.erb
MY EXHIBIT.RB (MODEL)
class Exhibit < ActiveRecord::Base
attr_accessible :content, :investigation_id, :name, :user_id, :media, :media_html
belongs_to :investigation
has_many :categorizations
has_many :categories, :through => :categorizations
validates :name, presence: true, length: { maximum: 140 }
validates :content, presence: true
default_scope -> { order('created_at DESC') }
auto_html_for :media do
html_escape
image
youtube(:width => 400, :height => 250)
link :target => "_blank", :rel => "nofollow"
simple_format
end
MY EXHIBIT CONTROLLER:
class ExhibitsController < ApplicationController
include AutoHtml
def new
#exhibit = Exhibit.new
end
def show
#exhibit = Exhibit.find(params[:id])
end
def index
#exhibits = Exhibit.paginate(page: params[:page])
end
def create
#investigation = Investigation.find(params[:investigation_id])
#exhibit = #investigation.exhibits.create(params[:exhibit])
if #exhibit.save
flash[:success] = "You've successfully added etc etc..."
redirect_to investigation_path(#investigation)
else
render 'new'
end
end
end
MY ROUTES.RB
resources :sessions, only: [:new, :create, :destroy]
resources :investigations do
resources :players
end
resources :investigations do
resources :exhibits
end
LASTLY MY SHOW.HTML.ERB (INVESTIGATION PROFILE)
<% #investigation.exhibits.each do |exhibit| %>
<div class="row-fluid services_circles">
<%= link_to #exhibit do %>
<div class="media">
<div class="pull-left">
<%= exhibit.media_html %>
</div>
<div class="media-body">
<h4 class="media-heading"><%= exhibit.name %></h4>
<p><%= exhibit.content %></p>
</div>
</div>
<% end %>
<% end %>
ADDED THE INVESTIGATIONS CONTROLLER
class InvestigationsController < ApplicationController
def new
#investigation = Investigation.new
end
def show
#investigation = Investigation.find(params[:id])
end
def index
#investigations = Investigation.paginate(page: params[:page])
end
def create
#investigation = Investigation.new(params[:investigation])
if #investigation.save
flash[:success] = "You've successfully created..."
redirect_to #investigation
else
render 'new'
end
end
end
ADDED THE INVESTIGATION MODEL
class Investigation < ActiveRecord::Base
# belongs_to :user
has_many :players, dependent: :destroy
has_many :exhibits, dependent: :destroy
default_scope -> { order('created_at DESC') }
end
I appreciate the help...if i need to post any more info just let me know
IN YOUR : app/contorollers/exhibits_controller.rb
def show
#investigation = Investigation.find(params[:investigation_id])
#exhibit = Exhibit.find(params[:id])
end
IN YOUR : app/views/exhibits/show.html.erb
<%= link_to investigation_exhibit_path(#investigation, #exhibit) do %>
Maybe, I think.

Resources