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).
Related
I wanted to add tags to my products in rails project, so i watched a youtube video how to do it (https://www.youtube.com/watch?v=rzx5MrCa0Pc&t=254s)
I did all he did, but i when i add a new product i get an error -
'New Product
1 error prohibited this product from being saved:
User must exist' , right above my new product form
how do i fix it.
MY ROUTES
Rails.application.routes.draw do
devise_for :users, :controllers => { :registrations => "registrations"}
resources :products
get 'home/ContactUs'
get 'home/Login'
get 'home/Store'
get 'home/blogs'
get 'home/index'
resources :home
root 'home#index'
MY PRODUCT MODEL
class Product < ActiveRecord::Base
belongs_to :user
has_many :taggings, dependent: :destroy
has_many :tags, through: :taggings
def self.tagged_with(name)
Tag.find_by!(name: name).products
end
def all_tags=(names)
# names="music, spotify"
self.tags = names.split(',').map do |name|
Tag.where(name: name).first_or_create!
end
end
def all_tags
tags.map(&:name).join(", ")
end
end
TAG MODEL
class Tag < ApplicationRecord
has_many :taggings, dependent: :destroy
has_many :products, through: :taggings
end
TAGGINGS MODEL
class Tagging < ActiveRecord::Base
belongs_to :product
belongs_to :tag
end
USER MODEL
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :products
end
PRODUCT_CONTROLLER
class ProductsController < ApplicationController
# before_action :authenticate_user!
before_action :set_product, only: [:show, :edit, :update, :destroy]
# GET /products
# GET /products.json
def index
if params[:tag]
#products = Product.tagged_with(params[:tag])
else
#products = Product.all
end
end
# GET /products/1
# GET /products/1.json
def show
end
# GET /products/new
def new
#product = Product.new
end
# GET /products/1/edit
def edit
end
# POST /products
# POST /products.json
def create
#product = Product.new(product_params)
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: 'Product was successfully created.' }
format.json { render :show, status: :created, location: #product }
else
format.html { render :new }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /products/1
# PATCH/PUT /products/1.json
def update
respond_to do |format|
if #product.update(product_params)
format.html { redirect_to #product, notice: 'Product was successfully updated.' }
format.json { render :show, status: :ok, location: #product }
else
format.html { render :edit }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
# DELETE /products/1
# DELETE /products/1.json
def destroy
#product.destroy
respond_to do |format|
format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_product
#product = Product.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def product_params
params.require(:product).permit(:filetype, :title, :img_url, :description, :all_tags, :price, :uploaded_by, :tutorial_url)
end
end
User must exist
The problem is Product belongs to User but you are trying to create the product without passing user_id which will create an orphan product
Solution: Change
def create
#product = Product.new(product_params)
to
def create
#product = current_user.products.new(product_params)
Also, You will need to change set_product method to make sure you can update or delete only products created by user
def set_product
#product = current_user.products.find(params[:id])
end
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 followed the instructions here to create a model Lesson in which there is a student and a teacher (both of the model User) and also a lesson start date.
#Lesson Controller
class Lesson < ActiveRecord::Base
belongs_to :student, class_name => 'User'
belongs_to :teacher, class_name => 'User'
end
#User Controller
class User < ActiveRecord::Base
has_many :lessons_to_attend, :class_name => 'Lesson', :foreign_key => 'student_id'
has_many :lessons_to_teach, :class_name => 'Lesson', :foreign_key => 'teacher_id'
end
The migration went smoothly and so on a page I try to query the student's lessons for tomorrow:
<% #date = 1.day.from_now %>
<%= #date.strftime("%A")%></br>
<%= #date.strftime("%-d/%-m/%y")%>
<% #user.lessons_to_attend.each do |l| %>
Lesson
<% end %>
But when I navigate to this page I get the error Uninitialized constant error Lesson::User
What did I miss out? I'll include the User controller in case something needs to be added in there.
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
# GET /users
# GET /users.json
def index
#users = User.all
end
# GET /users/1
# GET /users/1.json
def show
#user = User.find(params[:id])
end
# GET /users/new
def new
#user = User.new
end
# GET /users/1/edit
def edit
end
# POST /users
# POST /users.json
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { render :show, status: :ok, location: #user }
else
format.html { render :edit }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url, notice: 'User was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params[:user]
end
end
Two things:
belongs_to :student, class_name => 'User'
belongs_to :teacher, class_name => 'User'
Syntax error on class_name. That should either be :class_name => 'User' or class_name: 'User'.
The other thing is that I think you need to set your inverse_of on both sides of the association.
class Lesson < ActiveRecord::Base
belongs_to :student, class_name: 'User', inverse_of: :lessons_to_attend
belongs_to :teacher, class_name: 'User', inverse_of: :lessons_to_teach
end
class User < ActiveRecord::Base
has_many :lessons_to_attend, class_name: 'Lesson', foreign_key: 'student_id', inverse_of: :student
has_many :lessons_to_teach, class_name: 'Lesson', foreign_key: 'teacher_id', inverse_of: :teacher
end
Currently working on the Blog app in Ruby on Rails and encountered this error. This occurs whenever I attempt to view localhost:3000/posts/ via my browser.
Here's my posts_controller.rb file:
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
# GET /posts
# GET /posts.json
def index
#posts = Post.all
has_many :comments dependant: :destroy
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 action: 'show', status: :created, location: #post }
else
format.html { render action: '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 { 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.destroy
respond_to do |format|
format.html { redirect_to posts_url }
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, :body)
end
end
Any ideas?
It's only since I entered line 8 that I've had this problem.
has_many :comments dependant: :destroy
You missed , below :
has_many :comments, dependent: :destroy
Read has_many also to see the correct examples.
has_many :comments, dependent: :destroy
Goes in the Post model, not the controller
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.