I am stuck on a problem and i would love a hand! I got the polymorphic association from railscast #154
So far I have gotten the comment model working splendidly. However I want to create a rating model as well that I can then add js to make pretty.
Looked at every other tutorial/stackoverflows I could find. None of them show how to work with multiple polymorphic associations in a controller.
I tried to duplicate the code for the article_controller but I am not sure how to do that for both models. So far my attempts have been unsuccessful. The partial form has the proper name, it is _ratings.html.erb
My Error:
Missing partial ratings/ratings with {:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder, :coffee]}. Searched in:
* "/code/jimbo/bigdog/app/views"
* "/home/user/.rvm/gems/ruby-2.0.0-p247#lulla-core/gems/kaminari-0.14.1/app/views"
* "/home/user/.rvm/gems/ruby-2.0.0-p247#lulla-core/gems/devise-3.1.1/app/views"
My Models:
class Rating
include Mongoid::Document
include Mongoid::MultiParameterAttributes
field :value, type: Integer, default: "0"
belongs_to :rateable, polymorphic: true
end
My Controllers:
class RatingsController < ApplicationController
before_filter :load_rateable
def index
#ratings = #rateable.rating
end
def show
#rating = #rateable.ratings.find(params[:id])
respond_to do |format|
format.html # show.html.erb
end
end
def new
#rating = #rateable.rating.new
end
def create
#rating = #rateable.rating.new(params[:rating])
if #rating.save
redirect_to #rateable, notice: "Rating created."
else
render :new
end
end
private
def load_rateable
resource, id = request.path.split('/')[1, 2]
#rateable = resource.singularize.classify.constantize.find(id)
end
# def load_commentable
# klass = [Article, Photo, Event].detect { |c| params["#{c.name.underscore}_id"] }
# #rateable = klass.find(params["#{klass.name.underscore}_id"])
# end
end
Article Controller
class ArticlesController < ApplicationController
# GET /articles
# GET /articles.json
def index
#articles = Article.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #articles }
end
end
# GET /articles/1
# GET /articles/1.json
def show
#article = Article.find(params[:id])
#commentable = #article
#comments = #commentable.comments
#comment = Comment.new
respond_to do |format|
format.html # show.html.erb
format.json { render json: #article }
end
end
# GET /articles/new
# GET /articles/new.json
def new
#article = Article.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #article }
end
end
# GET /articles/1/edit
def edit
#article = Article.find(params[:id])
end
# POST /articles
# POST /articles.json
def create
#article = Article.new(params[:article])
respond_to do |format|
if #article.save
format.html { redirect_to #article, notice: 'Article was successfully created.' }
format.json { render json: #article, status: :created, location: #article }
else
format.html { render action: "new" }
format.json { render json: #article.errors, status: :unprocessable_entity }
end
end
end
# PUT /articles/1
# PUT /articles/1.json
def update
#article = Article.find(params[:id])
respond_to do |format|
if #article.update_attributes(params[:article])
format.html { redirect_to #article, notice: 'Article was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #article.errors, status: :unprocessable_entity }
end
end
end
# DELETE /articles/1
# DELETE /articles/1.json
def destroy
#article = Article.find(params[:id])
#article.destroy
respond_to do |format|
format.html { redirect_to articles_url }
format.json { head :no_content }
end
end
end
My View:
show.html (article)
<%= render "comments/comments" %>
<%= render "comments/form" %>
<%= render "ratings/ratings" %>
<%= render "ratings/form" %>
Routes:
resources :articles do
resources :comments
resources :ratings
end
Related
Hey Stackoverflow community (first time asking for help, searched a lot, found nothing specific for my problem, links appreciated).
I have the following structure:
Employees and Comments.
The Employee has this in its model:
has_many :comments, as: :commentable, dependent: :destroy
The Comment has this in its model:
belongs_to :commentable, polymorphic: true
I have a "show.html" view in the "Employee MVC". In this view I want to show an input textfield to add a comment to an employee. This is not working.
If I click submit, I get an undefined method `constantize' for nil:NilClass Error. (see image)
(On a seperate "new.html" in the "Comment MVC", I can create comments perfectly fine and add them to an employee).
Code:
show.html.slim for the Employee
h1
| Mitarbeiter
i<> = #employee.name
p Was für ein wundervoller Name!
hr
h2 Kommentare:
- #employee.comments.each do |comms|
p => comms.text
hr
**
= simple_form_for Comment.new do |f|
= f.input :text, label: "Neuer Kommentar: "
= f.hidden_field :commentable_id, value: #employee.id
= f.hidden_field :commentable_type, value: #employee.class
= f.submit class: 'btn btn-primary'**
a.btn.btn-success href=edit_employee_path(#employee)
| Bearbeiten
p
a.btn.btn-warning href=employees_path Zurück
class CommentsController < ApplicationController
before_action :set_comment, only: %i[ show edit update destroy ]
# GET /comments or /comments.json
def index
#comments = Comment.all
end
# GET /comments/1 or /comments/1.json
def show
end
# GET /comments/new
def new
klaz_name = params[:commentable_type]
thing_id = params[:commentable_id]
#thing = klaz_name.constantize.find(thing_id)
#comment = Comment.new
end
# GET /comments/1/edit
def edit
end
# POST /comments or /comments.json
def create
klaz_name = params[:commentable_type]
thing_id = params[:commentable_id]
#thing = klaz_name.constantize.find(thing_id)
#comment = Comment.new(comment_params.merge(commentable: #thing))
respond_to do |format|
if #comment.save
format.html { redirect_to comment_url(#comment), notice: "Comment was successfully created." }
format.json { render :show, status: :created, location: #comment }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /comments/1 or /comments/1.json
def update
respond_to do |format|
if #comment.update(comment_params)
format.html { redirect_to comment_url(#comment), notice: "Comment was successfully updated." }
format.json { render :show, status: :ok, location: #comment }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# DELETE /comments/1 or /comments/1.json
def destroy
#comment.destroy
respond_to do |format|
format.html { redirect_to comments_url, notice: "Comment was successfully destroyed." }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_comment
#comment = Comment.find(params[:id])
end
# Only allow a list of trusted parameters through.
def comment_params
params.require(:comment).permit(:text)
end
end
I tried to do it with a link_to and remote: true, but this didnt help either :/
In my Rails app, I have a comments scaffold which lets users comment on a movie.
I am faced with two problems.
The first problem is that anyone can create a comment, even if they are not signed in, how would I assign a comment to a user, so if there is a current_user, they can create a comment and I would be able to assign the user to the comment so <%= comment.user.first_name %>, and if they are not signed in, they cant create a comment. How would i do this? ( I am using devise )
The second problem is that when I create a comment, it takes me to this path (where 12 is :movie_id)
localhost:3000/movies/12/comments/new
This is fine but when i am creating the comment, I have to specify the movie_id (12), how this be done automatically, so rails sees that the movie_id for the comment is 12.
My Comments Controller, incase needed
class CommentsController < ApplicationController
# GET /comments
# GET /comments.json
before_filter :load_movie
def index
#comments = #movie.comments.all
#search = Movie.search(params[:q])
respond_to do |format|
format.html # index.html.erb
format.json { render json: #comments }
end
end
# GET /comments/1
# GET /comments/1.json
def show
#comment = Comment.find(params[:id])
#search = Movie.search(params[:q])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #comment }
end
end
# GET /comments/new
# GET /comments/new.json
def new
#comment = Comment.new
#search = Movie.search(params[:q])
respond_to do |format|
format.html # new.html.erb
format.json { render json: #comment }
end
end
# GET /comments/1/edit
def edit
#comment = Comment.find(params[:id])
#search = Movie.search(params[:q])
end
# POST /comments
# POST /comments.json
def create
#comment = Comment.new(params[:comment])
#search = Movie.search(params[:q])
respond_to do |format|
if #comment.save
format.html { redirect_to :back }
format.json { render json: #comment, status: :created, location: #comment }
else
format.html { render action: "new" }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# PUT /comments/1
# PUT /comments/1.json
def update
#comment = Comment.find(params[:id])
#search = Movie.search(params[:q])
respond_to do |format|
if #comment.update_attributes(params[:comment])
format.html { redirect_to (#movie), notice: 'Comment was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# DELETE /comments/1
# DELETE /comments/1.json
def destroy
#comment = Comment.find(params[:id])
#comment.destroy
respond_to do |format|
format.html { redirect_to comments_url }
format.json { head :no_content }
end
end
private
def load_movie
#movie = Movie.find_by_id(:movie_id)
end
end
First:
using devise, you can request that a user is signed in by saying at the top of your controller:
before_filter :authenticate_user!, only: [:new,:create]
so if someone not signed in tries to access these actions, they are redirected to the sign in page and after sign in forwarded to the original request.
Second:
As you can see from the routes, 12 is assigned to params[:movie_id]. So in your controllers new action write:
#movie = Movie.find(params[:movie_id])
#comment = #movie.comments.new
#comment.user=current_user
I have a Topic which has_many Posts. Each Post belongs to a User, and each User has_one Profile.
In my "show" page for a specific Topic, I try to display profile information of the user who created the post:
<% #topic.posts.each do |post| %>
<%= post.user.profile.first_name %>
<% end %>
I get the following error:
undefined method `profile' for nil:NilClass
Any idea why it does not allow me to access the profile? Please advise.
My Topic controller is as follows:
class TopicsController < ApplicationController
# GET /topics
# GET /topics.json
add_breadcrumb :index, :topics_path
def index
if params[:tag]
#topics = Topic.tagged_with(params[:tag])
else
#topics = Topic.all
end
#newtopic = Topic.new
respond_to do |format|
format.html # index.html.erb
format.json { render json: #topics }
end
end
# GET /topics/1
# GET /topics/1.json
def show
#topic = Topic.find(params[:id])
#posts = #topic.posts
#newpost = #topic.posts.build
add_breadcrumb #topic.name
respond_to do |format|
format.html # show.html.erb
format.json { render json: #topic }
end
end
# GET /topics/new
# GET /topics/new.json
def new
add_breadcrumb :new, :topics_path
#topic = Topic.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #topic }
end
end
# GET /topics/1/edit
def edit
#topic = Topic.find(params[:id])
end
# POST /topics
# POST /topics.json
def create
#topic = Topic.new(params[:topic])
#topic.user_id = current_user.id
#topic.last_poster_id = current_user.id
#topic.last_post_at = Time.now
respond_to do |format|
if #topic.save
format.html { redirect_to #topic, notice: 'Topic was successfully created.' }
format.json { render json: #topic, status: :created, location: #topic }
else
format.html { render action: "new" }
format.json { render json: #topic.errors, status: :unprocessable_entity }
end
end
end
# PUT /topics/1
# PUT /topics/1.json
def update
#topic = Topic.find(params[:id])
respond_to do |format|
if #topic.update_attributes(params[:topic])
format.html { redirect_to #topic, notice: 'Topic was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #topic.errors, status: :unprocessable_entity }
end
end
end
# DELETE /topics/1
# DELETE /topics/1.json
def destroy
#topic = Topic.find(params[:id])
#topic.destroy
respond_to do |format|
format.html { redirect_to topics_url }
format.json { head :no_content }
end
end
end
Your error is caused by this line in the show action #topic.posts.build and this line in the view #topic.posts.each. Since you are building a new post in the controller, #topic.posts includes that new record which most probably have the user as nil. So the solution to your problem is to use #posts instead of #topic.posts in your view.
Check your database. Its very likely that in your database there is a post which corresponds to no user. Since the user for that post is none, the profile becomes undefined for nil:NilClass which is user(null).
This happens mostly when you creates the post that belongs to user but then you deletes the user that belongs to that post from database.
The correct way is to impose a constraint in your user model that should be-
class Post
belongs_to :user, :dependent => :destroy
end
So if the user gets deleted, the corresponding posts of that user also get deleted.
Please note that it is not a good practice to directly delete records from database after imposing the relationship between them using tables.
I am trying a an simple association which should work. I followed the tutorial at http://ruby.railstutorial.org/chapters/ and at chapter 10
Here what I have wrote down
model/customer
class Customer < ActiveRecord::Base
has_many :posts, dependent: :destroy
attr_accessible :name, :email, :password, :password_confirmation
has_secure_password
model/post
class Post < ActiveRecord::Base
belongs_to :customer
attr_accessible :description, :post_finish_at, :post_how, :post_location
controller/customers
class CustomersController < ApplicationController
before_filter :signed_in_customer, only: [:edit, :update]
before_filter :correct_customer, only: [:edit, :update]
def index
#customers = Customer.all
end
def show
#customer = Customer.find(params[:id])
#posts = #customer.posts
end ...
controller/post -- should be irrelevant since i am doing a partial
class PostsController < ApplicationController
# GET /posts
# GET /posts.json
def index
#posts = Post.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #posts }
end
end
# GET /posts/1
# GET /posts/1.json
def show
#post = Post.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #post }
end
end
# GET /posts/new
# GET /posts/new.json
def new
#post = Post.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #post }
end
end
# GET /posts/1/edit
def edit
#post = Post.find(params[:id])
end
# POST /posts
# POST /posts.json
def create
#post = Post.new(params[:post])
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render json: #post, status: :created, location: #post }
else
format.html { render action: "new" }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PUT /posts/1
# PUT /posts/1.json
def update
#post = Post.find(params[:id])
respond_to do |format|
if #post.update_attributes(params[:post])
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post = Post.find(params[:id])
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url }
format.json { head :no_content }
end
end
end
view/customer/show.html.erb
<div class="posts">
<%= render 'posts/post'%>
</div>
view/post/_post.html.erb
<li>
<%= #posts.each do |post| %>
<%= post.title %>
<% end %>
</li>
Here what the output look like
[]
Why?
Thanks
It looks to me like you've got a couple things wrong. First, the partial (view/post/_post.html.erb) should be rendering a single post, not the whole collection of them. Second problem is that you're not passing anything to the partial.
There's a handy shorthand for rendering collections, where if you just render the collection, it will automatically look for a partial with the same name and render it for each model in the collection.
See: http://guides.rubyonrails.org/layouts_and_rendering.html#using-partials
So I think this should do what you want (I added <ul></ul> tags to make it an unordered list):
view/customer/show.html.erb
<div class="posts">
<ul>
<%= render #posts %>
</ul>
</div>
view/post/_post.html.erb
<li>
<%= post.title %>
</li>
It looks like customer doesn't have a posts association, but only an events association. I'd start there
When I press new on my Jobs form in seeing an error that it could not find 'create' in my JobsController.
Unknown action
The action 'create' could not be found for JobsController
Here' my controller:
class JobsController < ApplicationController
private
def load_clients
#clients = collection_select :client, :client_id
end
def index
#job = Job.find(:all)
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #job }
end
end
def create
#job = Job.new(params[:job])
respond_to do |format|
if #job.save
format.html { redirect_to #job, notice: 'Job was successfully created.' }
format.json { render json: #job, status: :created, location: #job }
else
format.html { render action: "new" }
format.json { render json: #job.errors, status: :unprocessable_entity }
end
end
end
def show
#job = Job.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #job }
end
end
end
As you can see. It' clearly there. Why is Rails not seeing it?
It is because you assign the create method as private.
Try redefine your controller this way.
Here' my controller:
class JobsController < ApplicationController
def index
...
end
def create
...
end
def show
...
end
private
def load_clients
#clients = collection_select :client, :client_id
end
end