Need advice
I'm using rails 4 and ruby 1.9.3
I'm trying create post on admin, with validation for title and content presence. but when i create the post the error of validation raise, even if i fill for title and content.
this is my code
post.rb
class Post < ActiveRecord::Base
validates :title, :presence => true
validates :content, :presence => true
validates :user_id, :presence => true
...
posts_controller.rb
module Admin
class PostsController < ::ApplicationController
layout 'admin'
before_action :set_post, only: [:show, :edit, :update, :destroy, :publish, :unpublish]
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
#post.user = current_user
respond_to do |format|
if #post.save
format.html { redirect_to admin_post_path(#post), notice: 'Post was successfully created.' }
format.json { render action: 'show', status: :created, location: #post }
else
format.html { render action: 'new' }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.friendly.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:title, :content, :published)
end
end
end
and in my log raise WARNING: Can't mass-assign protected attributes for Post: title, content.
Thank's
Related
I'm trying to build an app where people can specify what posts need to be read before this one and here I'm trying to show them.
<%= #post.before.each do |before| %>
<li><%= before.title %></li>
<% end %>
This gets me this error:
SQLite3::SQLException: no such column: connections.post_id: SELECT "posts".* FROM "posts" INNER JOIN "connections" ON "posts"."id" = "connections"."after_id" WHERE "connections"."post_id" = ?
There isn't supposed to be a post_id column in connections, there is supposed to be an before_id column in it.
My models are:
post.rb:
class Post < ApplicationRecord
has_many :connections
has_many :before, through: :connections, source: :after, foreign_key: "before_id"
has_many :after, through: :connections, source: :before, foreign_key: "after_id"
end
connection.rb
class Connection < ApplicationRecord
belongs_to :before, class_name: "Post", foreign_key: "before_id"
belongs_to :after, class_name: "Post", foreign_key: "after_id"
end
The controller code for posts - automatically generated with scaffolding:
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
# GET /posts
# GET /posts.json
def index
#posts = Post.all
end
# GET /posts/1
# GET /posts/1.json
def show
end
# GET /posts/new
def new
#post = Post.new
end
# GET /posts/1/edit
def edit
end
# POST /posts
# POST /posts.json
def create
#post = Post.new(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: #post }
else
format.html { render :edit }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
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(:title, :text)
end
end
has_many :connections in your Post model is telling Rails that you have a post_id on the connections table. If this is not the case, I recommend deleting the association or defining a foreign_key for the association.
I would recode your model as follows:
class Post < ApplicationRecord
has_many :before, class_name: 'Connection', foreign_key: "before_id"
has_many :after, class_name: 'Connection', foreign_key: "after_id"
end
NOTE: You have source: :before and source: :after set opposite their respective association names and foreign_key names. I suspect that was not intentional. However, if it was intentional, you may want to swap foreign_keys between your two associations (i.e put the before_id on the after association and vis versa).
I'm attempting to create a Rails blog application and am having some issues implementing friendly urls. (Not the via the gem, I'm manually implementing them.) I am able to access the article's show page, however when I attempt to like/unlike the article or post a comment to the article, I'm getting this error: ActiveRecord::RecordNotFound. Here is the code snippet that it flags:
Extracted source (around line #19)
def set_article
#article = Article.find_by!(slug: params[:id])
end
end
Here are my three controllers where this is implemented:
class ArticlesController < ApplicationController
before_action :require_signin, except: [:index, :show]
before_action :require_admin, except: [:index, :show]
before_action :set_article, only: [:show, :edit, :update, :destroy]
# GET /articles
# GET /articles.json
def index
#articles = Article.all
end
# GET /articles/1
# GET /articles/1.json
def show
#likers = #article.likers
if current_user
#current_like = current_user.likes.find_by(article_id: #article.id)
end
#tags = #article.tags
end
# GET /articles/new
def new
#article = Article.new
end
# GET /articles/1/edit
def edit
end
# POST /articles
# POST /articles.json
def create
#article = Article.new(article_params)
respond_to do |format|
if #article.save
format.html { redirect_to #article, notice: 'Article was successfully created.' }
format.json { render :show, status: :created, location: #article }
else
format.html { render :new }
format.json { render json: #article.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /articles/1
# PATCH/PUT /articles/1.json
def update
respond_to do |format|
if #article.update(article_params)
format.html { redirect_to #article, notice: 'Article was successfully updated.' }
format.json { render :show, status: :ok, location: #article }
else
format.html { render :edit }
format.json { render json: #article.errors, status: :unprocessable_entity }
end
end
end
# DELETE /articles/1
# DELETE /articles/1.json
def destroy
#article.destroy
respond_to do |format|
format.html { redirect_to articles_url, notice: 'Article was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_article
#article = Article.find_by!(slug: params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def article_params
params.require(:article).permit(:slug, :title, :content, tag_ids: [])
end
end
class LikesController < ApplicationController
before_action :require_signin
before_action :set_article
def create
#article.likers << current_user
redirect_to #article, notice: "Thanks for liking!"
end
def destroy
like = current_user.likes.find(params[:id])
like.destroy
redirect_to #article, notice: "Sorry you unliked it!"
end
private
def set_article
#article = Article.find_by!(slug: params[:id])
end
end
class CommentsController < ApplicationController
before_action :set_article
before_action :set_comment, only: [:edit, :update, :destroy]
# GET /comments
# GET /comments.json
def index
#comments = #article.comments
end
# GET /comments/new
def new
#comment = #article.comments.new
end
# GET /comments/1/edit
def edit
end
# POST /comments
# POST /comments.json
def create
#comment = #article.comments.new(comment_params)
respond_to do |format|
if #comment.save
format.html { redirect_to #article, notice: 'Comment was successfully created.' }
format.json { render :show, status: :created, location: #article }
else
format.html { render :new }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /comments/1
# PATCH/PUT /comments/1.json
def update
respond_to do |format|
if #comment.update(comment_params)
format.html { redirect_to article_path(#article), notice: 'Comment was successfully updated.' }
format.json { render :show, status: :ok, location: article_comments_path(#article) }
else
format.html { render :edit }
format.json { render json: #article.comments.errors, status: :unprocessable_entity }
end
end
end
# DELETE /comments/1
# DELETE /comments/1.json
def destroy
#article.comments.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_article
#article = Article.find_by!(slug: params[:id])
end
def set_comment
#comment = Comment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def comment_params
params.require(:comment).permit(:post)
end
end
Here is the Article Model
class Article < ActiveRecord::Base
before_validation :generate_slug
has_many :comments, dependent: :destroy
has_many :likes, dependent: :destroy
has_many :likers, through: :likes, source: :user
has_many :characterizations, dependent: :destroy
has_many :tags, through: :characterizations
belongs_to :user
validates :title, presence: true, uniqueness: true
validates :content, presence: true
validates :slug, uniqueness: true
def to_param
slug
end
def generate_slug
self.slug ||= title.parameterize if title
end
end
I'm not sure why it's having issues. Any help would be appreciated!
It seems you don't have article with slug value params[:id] in you database, that's why it throws error. You are using find_by! and it throws error if no record found.
In your LikesController
...
private
def set_article
#article = Article.find_by!(slug: params[:article_id])
end
...
# You need to use params[:article_id] not params[:id], because in your route for like it is set as article_id
# If same set up for comments then just change params[:id] -> params[:article_id]
I'm working on creating a basic survey app as I'm learning rails. I've setup a has_many through relationship between the surveys as the questions (as questions may be used in multiple surveys). I've been struggling with adding a question to a survey though. Any idea what I need to do to create a new surveytization when creating my new question (and thus adding the question to the survey)? I'm able to do it in the console but am struggling with translating that to the controllers/views/params - if you know of any good documentation about those I'd love to check them out to (but thus far haven't found much).
It seems to error out when I try to assign my #survey variable using the :survey_id in the params I'm sending to the Question controller.
I really appreciate your help!
Question.rb:
class Question < ActiveRecord::Base
has_many :answers, dependent: :delete_all
validates :title, presence: true
has_many :surveytizations
has_many :surveys, :through => :surveytizations
end
Survey.rb
class Survey < ActiveRecord::Base
has_many :surveytizations
has_many :questions, :through => :surveytizations
end
Surveytization.rb:
class Surveytization < ActiveRecord::Base
has_many :surveys
has_many :questions
validates :survey_id, presence: true
validates :question_id, presence:true
end
SurveyController.rb:
class SurveysController < ApplicationController
before_action :set_survey, only: [:show, :edit, :update, :destroy]
before_action :set_question
# GET /surveys
# GET /surveys.json
def index
#surveys = Survey.all
end
# GET /surveys/1
# GET /surveys/1.json
def show
end
# GET /surveys/new
def new
#survey = Survey.new
end
# GET /surveys/1/edit
def edit
end
# POST /surveys
# POST /surveys.json
def create
#survey = Survey.new(survey_params)
respond_to do |format|
if #survey.save
format.html { redirect_to #survey, notice: 'Survey was successfully created.' }
format.json { render action: 'show', status: :created, location: #survey }
else
format.html { render action: 'new' }
format.json { render json: #survey.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /surveys/1
# PATCH/PUT /surveys/1.json
def update
respond_to do |format|
if #survey.update(survey_params)
format.html { redirect_to #survey, notice: 'Survey was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #survey.errors, status: :unprocessable_entity }
end
end
end
# DELETE /surveys/1
# DELETE /surveys/1.json
def destroy
#survey.destroy
respond_to do |format|
format.html { redirect_to surveys_url }
format.json { head :no_content }
end
end
def add_question(question)
surveytizations.create!(question_id: question.id)
end
def remove_question(question)
surveytizations.find_by(question_id: question.id).destroy
end
def find_question(question)
#question = surveytizations.find_by(question_id: question.id)
end
private
# Use callbacks to share common setup or constraints between actions.
def set_survey
#survey = Survey.find(params[:id])
end
def set_question
#question = Question.new
end
# Never trust parameters from the scary internet, only allow the white list through.
def survey_params
params.require(:survey).permit(:title)
end
end
Survey show.html.erb:
<p id="notice"><%= notice %></p>
<p>
<strong>Title:</strong>
<%= #survey.title %>
</p>
<%= link_to 'Edit', edit_survey_path(#survey) %> |
<%= link_to 'Back', surveys_path %>
<%= link_to "Add Question", new_question_path(:survey_id => #survey.id)%>
QuestionController:
class QuestionsController < ApplicationController
before_action :set_question, only: [:show, :edit, :update, :destroy]
# GET /questions
# GET /questions.json
def index
#questions = Question.all
end
# GET /questions/1
# GET /questions/1.json
def show
#answers = #question.answers
end
# GET /questions/new
def new
#question = Question.new
#survey = Survey.find(:survey_id)
end
# GET /questions/1/edit
def edit
end
# POST /questions
# POST /questions.json
def create
#question = Question.new(question_params)
respond_to do |format|
if #question.save
format.html { redirect_to #question, notice: 'Question was successfully created.' }
format.json { render action: 'show', status: :created, location: #question }
else
format.html { render action: 'new' }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /questions/1
# PATCH/PUT /questions/1.json
def update
respond_to do |format|
if #question.update(question_params)
format.html { redirect_to #question, notice: 'Question was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
# DELETE /questions/1
# DELETE /questions/1.json
def destroy
#question.destroy
respond_to do |format|
format.html { redirect_to questions_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_question
#question = Question.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def question_params
params.require(:question).permit(:title, :single_response, :surveytization)
end
end
One problem is your join relation should have belongs_to instead of has_many, to get the has_many through working:
class Surveytization < ActiveRecord::Base
belongs_to :survey
belongs_to :question
validates :survey_id, presence: true
validates :question_id, presence:true
end
Notice the :survey and :question are singular name in the belongs_to
To Add a question to a survey you can
# create new question or find existing question and store it in #question
#question
# get the survey into #survey
#survey
#survey.questions << #question
This will magically create the surveytization as well. Now that question will belong to that survey.
You Don't even have to call #survey.save! after.
I'm very new to Ruby on Rails and I'm struggling with my scaffolded controller.
I made a nested resource where my comments are placed in posts.
class Post < ActiveRecord::Base
validates :name, :presence => true
validates :title, :presence => true, :length => { :minimum => 5 }
has_many :comments
end
class Comment < ActiveRecord::Base
validates :commenter, :presence => true
validates :body, :presence => true
belongs_to :post
end
A simplified version of the controller is
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :edit, :update, :destroy]
# omited new, index, show...
# POST /comments
# POST /comments.json
def create
post = Post.find(params[:post_id])
#comment = post.comments.create(params[:comment].permit(:name, :title, :context))
respond_to do |format|
if #comment.save
format.html { redirect_to([#comment.post, #comment], notice: 'Comment was successfully created.') }
format.json { render action: 'show', status: :created, location: #comment }
else
format.html { render action: 'new' }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /comments/1
# PATCH/PUT /comments/1.json
def update
post = Post.find(params[:post_id])
#comment = post.comments.find(params[:comment])
respond_to do |format|
if #comment.update(comment_params)
format.html { redirect_to #comment, 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
private
# Use callbacks to share common setup or constraints between actions.
def set_comment
#comment = Comment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def comment_params
params.require(:comment).permit(:commenter, :body, :post)
end
end
When i filled in the form, i get this exception:
2 errors prohibited this comment from being saved:
Commenter can't be blank
Body can't be blank
I tried this guide but i think it isn't 100% compatible with Rails 4.
You are reading from params attributes for a Post (:name, :title, :context), but you need to read Comments attributes (:commenter, :body)
replace this:
#comment = post.comments.create(params[:comment].permit(:name, :title, :context))
with
#comment = post.comments.create(params[:comment].permit(:commenter, :body))
or, much better, with:
#comment = post.comments.create(comment_params)
It appears that you are explicitly permitting different set of attributes in your create action.
You should update your create action to use comment_params like you've done in update action. The reason being your Comment is definitely expecting Commenter and Body and not :name, :title, :context which you've permitted in your create action.
Update controller's create action as:
# POST /comments
# POST /comments.json
def create
...
#comment = post.comments.create(comment_params)
...
end
I'm creating my own blog on Rails with posts and users. I need to show all posts from specific author when I click on him (here the concept:link). What should I do for this?
Please say what extra information or code should I add
users_controller:
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
#posts = #user.posts
end
end
posts_controller:
class PostsController < ApplicationController
before_filter :authenticate_user!, :except => [:show, :index]
# 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])
#post = current_user.posts.build(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
user model:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
has_many :posts, :dependent => :destroy
validates :fullname, :presence => true, :uniqueness => true
validates :password, :presence => true
validates :email, :presence => true, :uniqueness => true
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation, :fullname
end
post model:
class Post < ActiveRecord::Base
attr_accessible :text, :title
validates :user_id, :presence => true
validates :title, :presence => true
validates :text, :presence => true
belongs_to :user
has_many :comments
end
This is a fairly straight forward use of Ruby on Rails. I recommend reading Active Record Basics to get up to speed.
First, you should have a belongs_to relationship between Posts and Users that looks like this:
class User < ActiveRecord::Base
has_many :posts
end
class Post < ActiveRecord::Base
belongs_to :user
end
This adds a .posts method to the User instance and a .user method to the Post instance.
Then you have to make a decision about how you want the URL structure of your application to work. Here are a few options from the top of my head:
/posts?user=:user_id
/posts/by/:user_id
/users/:id/posts
Given the relationship between a User and their Posts, my recommendation (and I believe the general "Rails Way") would be #3. So, let's add the routes to config/routes.rb:
The short way to create JUST that route:
get 'users/:id/posts' => 'users#posts', :as => :user_posts
The long way to create the route based on resources:
resources :users do
member do
get :posts
end
end
Both approaches will provide a helper method called user_posts_path and one called user_posts_url which can be used in your view to link to the list of user posts using the link_to helper method:
<%= link_to post.user.name, user_posts_path(post.user) %>
Now, you have to add the controller action in app/controllers/users_controller.rb:
class UsersController < ActionController::Base
def posts
#user = User.find(params[:id])
#posts = #user.posts
end
end
and then add your HTML/ERB code to app/views/users/posts.html.erb
<% #posts.each do |post| %>
<%= post.inspect %>
<% end %>
That should give you the basic ability to show a user's posts. You can enhance it by reusing a post partial or some other nice shortcuts, but I'll leave that as an exercise for you to figure out.
You need 2 models: User and Post. There is a relation between them: User HAS MANY posts, post BELONGS TO user. To create this relation in a database you should add user_id column to posts table. To do this simply run the following command:
rails generate migration AddUserIdToPosts user_id: integer
Don't forget to run rake db:migrate after that
To create association between models add to the User model:
has_many :posts, dependent: :destroy
And to Post model:
belongs_to :user
Now you can use 'user' method on post and 'posts' method on user. For example in show action of users controller:
#user = User.find(params[:id])
#posts = #user.posts
This links will help you:
http://guides.rubyonrails.org/association_basics.html
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html