I have the Teacher model, and I am using the searchkick for this model. The first problem is when I search for a particular teacher, if the teacher is in model, it will not only return that teacher but also the rest of the teachers in my model. I did some research on the internet and couldn't find the solution for my case. Therefore, I really need your help guys.
Here are some of my files, just in case you need to see them, and I think you do.
teachers_controller.rb:
class TeachersController < ApplicationController
before_action :find_school
before_action :find_teacher, only: [:show, :edit, :update, :destroy]
def show
end
def search
if params[:search].present?
#teachers = #school.teachers.search(params[:search], fields: [{fullName: :exact}])
else
#teachers = []
end
end
def new
#teacher = #school.teachers.build
end
def create
#teacher = #school.teachers.create(teacher_params)
#teacher.save
redirect_to(#school)
end
def edit
end
def update
#teacher.update(teacher_params)
redirect_to(#school)
end
private
def find_school
#school = School.find(params[:school_id])
end
def find_teacher
#teacher = Teacher.find(params[:id])
end
def teacher_params
params.require(:teacher).permit(:firstName, :lastName, :middleName, :department, :school_id)
end
end
search.html.haml:
.text-center
/ No search results announcement/notification
- if #teachers.blank?
%h2 Xin lỗi, hệ thống chúng tôi không có thông tin về giảng viên mà bạn muốn tìm.
- else
- #school.teachers.each do |teacher|
%h2= link_to teacher.to_s, school_teacher_path(#school, teacher)
%br/
.text-center
= link_to("Trang Trước", school_url(#school), class: "btn btn-default btn-xs")
= link_to("Trang Chủ", root_path, class: "btn btn-default btn-xs")
teacher.rb:
class Teacher < ActiveRecord::Base
belongs_to :school
has_many :ratings
searchkick word_start: [:firstName, :lastName, :middleName]
def name
"#{lastName} #{middleName} #{firstName}"
end
def to_s
name
end
end
routes.rb:
Rails.application.routes.draw do
devise_for :users
resources :schools do
collection do
get 'search'
end
resources :teachers do
collection do
get 'search'
end
end
end
resources :teachers do
resources :ratings
end
root 'schools#index'
end
Related
I would like to add "category" function.
I associated article.rb and category.rb.
However, undefined method `categories' for nil:NilClass was present.
I have no idea.If you know any solution, please tell me.
Index.html.erb
<% unless #article.categories.blank? %>
<% #articles.categories.each do |category|%>
<%= link_to category.name,article_path(category_id:category.id)%>
<%end%>
<%end%>
article.rb
class Article < ApplicationRecord
scope :from_category, -> (category_id) { where(id: article_ids = ArticleCategory.where(category_id: category_id).select(:article_id))}
validates :title, presence: true
validates :content, presence: true
mount_uploader :image,ImageUploader
has_many :categories, through: :article_categories
has_many :article_categories, dependent: :destroy
def save_categories(tags)
current_tags = self.categoires.pluck(:name) unless self.categories.nil?
old_tags = current_tags - tags
new_tags = tags - current_tags
old_tags.each do |old_name|
self.categories.delete Category.find_by(name:old_name)
end
new_tags.each do |new_name|
article_category = Category.find_or_create_by(name:new_name)
self.categories << article_category
end
end
end
category.rb
class Category < ApplicationRecord
validates :name,presense: true,length:{maximum:50}
has_many :articles,through: :article_categories
has_many :article_categories,dependent: :destroy
end
article_category.rb
class ArticleCategory < ApplicationRecord
belongs_to :article
belongs_to :category
validates :article_id,presense:true
validates :category_id,presense:true
end
articles_controller.rb
class ArticlesController < ApplicationController
before_action :set_post, only: [:show,:edit,:update]
before_action :authenticate_user!, :except => [:index,:show]
before_action :set_article_tags_to_gon, only: [:edit]
def index
if params[:category_id]
#selected_category = Category.find(params[:category_id])
#articles= Article.from_category(params[:category_id]).page(params[:page])
else
#articles= Article.all.page(params[:page])
end
#articles = Article.page params[:page]
end
def show
end
def new
#article = Article.new
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to articles_path
else
render 'articles/new'
end
end
def edit
#category_list = #article.categories.pluck(:name).join(",")
end
def update
if #article.update(article_params)
redirect_to articles_path
else
redirect_to 'edit'
end
end
private
def article_params
params[:article].permit(:title,:content,:image,:tag_list,:category)
end
def set_post
#article = Article.find(params[:id])
end
error message
You're calling categories on a nil object, in this case #article. Did you mean to call it on #articles?
If not, you will need to define #article in the index action of your controller.
Hello I have an exercise app where a user should be able to Like some products.
I could find a way to display the product he liked, but I really can't figure how to create and make work the like button.
I am not using any gem, I wan't to understand how to do it from Scratch.
Here are my models:
class User < ApplicationRecord
has_many :likes
has_many :liked_products, through: :likes, source: :product
end
class Product < ApplicationRecord
has_many :likes
end
class Like < ApplicationRecord
belongs_to :user
belongs_to :product
end
In my view product show where I want the like button:
<h1><%= #product.name %></h1>
<%= link_to "Like", product_likes_path(#product), method: :put, remote: true %>
my routes:
Rails.application.routes.draw do
root to: 'visitors#index'
devise_for :users
resources :users
resources :products do
resource :likes
end
end
That's my products controller, I think things must come in here but I don't know HOW!
class ProductsController < ApplicationController
before_action :find_product, only: :show
def index
#products = Product.all
end
def show
##product.like => gives an error 404
end
private
def find_product
#product = Product.find(params[:id])
end
end
I had created a likes controller but it seems it is not useful.... So... I gave up there...
class LikesController < ApplicationController
def new
#like = Like.new(like_params)
end
def create
#like = Like.new(like_params)
end
private
def like_params
params.require(:likes).permit(:user_id, :product_id)
end
end
I would really enjoy some light on this please :)
Finally found out how to set the controller
class LikesController < ApplicationController
def create
#user = current_user.id
#product = params[:product_id]
likes = {user_id: #user, product_id: #product}
#like = Like.new(likes)
#like.save!
if #like.save
redirect_to user_path(#user)
else
redirect_to product_path
end
end
end
the buttton
<%= link_to "Like", product_likes_path(#product), method: :post %>
routes
Rails.application.routes.draw do
root to: 'products#index'
devise_for :users
resources :users
resources :users do
resources :products do
resources :likes
end
end
end
You could try something along these lines:
Routes:
Rails.application.routes.draw do
root to: 'visitors#index'
devise_for :users
resources :users do
resources :products do
resources :likes
end
end
resources :products do
resource :likes
end
end
Which will give you something like:
... other routes ...
user_product_likes GET /users/:user_id/products/:product_id/likes(.:format) likes#index
POST /users/:user_id/products/:product_id/likes(.:format) likes#create
new_user_product_like GET /users/:user_id/products/:product_id/likes/new(.:format) likes#new
edit_user_product_like GET /users/:user_id/products/:product_id/likes/:id/edit(.:format) likes#edit
user_product_like GET /users/:user_id/products/:product_id/likes/:id(.:format) likes#show
PATCH /users/:user_id/products/:product_id/likes/:id(.:format) likes#update
PUT /users/:user_id/products/:product_id/likes/:id(.:format) likes#update
DELETE /users/:user_id/products/:product_id/likes/:id(.:format) likes#destroy
... other routes ...
Then:
<%= link_to "Like", user_product_likes_path(#user, #product), method: :post, remote: true %>
And in your LikesController:
class LikesController < ApplicationController
def new
#like = Like.new(like_params)
end
def create
#like = Like.new(like_params)
if #like.save
... do something happy
else
... do something sad
end
end
private
def like_params
params.require(:likes).permit(:user_id, :product_id)
end
end
Untested, so buyer beware. You might need to fiddle with your like_params and other stuff.
I want to the category I create in relation with the post I want to create. I don't want to add a gem or anything else I think we can do it with has_manyand belongs_to
I create two tables Posts and Category and I want to choose a category in a collection and this is written in the post new#view I want to create and on the post show#view and post index#view.
Models for posts is :
class Post < ActiveRecord::Base
belongs_to :user
belongs_to :category
TAGS = ["Design", "Mode", "Tendance", "Life-Style", "Tradition", "Gastronomie", "Insolite", "Technologie"]
validates :tag, inclusion: { in: Post::TAGS, allow_nil: false }
mount_uploader :cover, ImageUploader
end
and categories is foreign keys for posts here is the model
class Category < ActiveRecord::Base
has_many :posts
NAMES = ["JAPON", "CHINE", "INDE"]
validates :name, inclusion: { in: Category::NAMES, allow_nil: false }
end
Posts Controllers are here
class PostsController < ApplicationController
before_filter :authenticate_user!, except: [:index, :show]
before_action :find_post, only: [:show, :edit, :update, :destroy]
def index
#posts = Post.all
end
def show
# #alert_message = "Vous lisez #{#post.title}"
end
def new
# if current_user and current_user.admin?
#post = Post.new
# else
# redirect_to posts_path
# end
end
def create
# if current_user and current_user.admin?
#post = current_user.posts.new(post_params)
##post = current_user.posts.new(post_params)
if #post.save
redirect_to #post
else
render :new
end
# else
# render 'shared/404.html.erb'
# end
end
def edit
end
def update
if #post.update(post_params)
redirect_to #post
else
render :edit
end
end
def destroy
#post.destroy
redirect_to :back
end
private
def find_post
#post = Post.find(params[:id])
end
# def set_category
# #post_category = Category.find(params[:category_id])
# end
def post_params
params.require(:post).permit(:title, :subtitle, :introduction, :body, :cover, :tag, :category_id)
end
end
and categories_controller are here
class CategoriesController < ApplicationController
before_action :set_category, only: [:show, :new, :create, :destroy]
def show
#category = Category.find(params[:id])
end
def index
#categories = Category.all
end
def create
#category = Category.new(category_params)
if #category.save
redirect_to #post
else
render :new
end
end
def new
#category = Category.new
end
def edit
end
def update
end
def destroy
#category = Category.find(params[:id])
#category.destroy
redirect_to post_path(#post)
end
private
# def set_post
# #post = Post.find(params[:post_id])
# end
# def set_category
# #category = Category.find(params[:category_id])
# end
def set_category
if params[:id].present?
#category = Category.find(params[:id])
else
#category = Category.new
end
end
# def find_category
# #category = Category.find(params[:id])
# end
def category_params
params.require(:category).permit(:name, :description)
end
end
Please could you show the right way to add a category I choose in collection and I show in post new#view show#view index#view.
Thank you for your help.
If a category can belong to more than one post, I would recommend using a has_may_through relationship for your data model.
class Post
has_many :post_categories
has_many :categories, through: post_categories
accepts_nested_attributes_for :categories
end
class Category
has_many :post_categories
has_many :posts, through: post_categories
end
class PostCategory
belongs_to :posts
belongs_to :categories
end
You will need to create a migration to add the 'through' table, PostCategory, which will consist of a post_id and a category_id.
In the controller
def new
#post = Post.new
#post.categories.build
end
def post_params
params.require(:post).permit(:title, :subtitle, :introduction, :body, :cover, :tag, category_ids: [])
end
In your form, you can use fields_for to build the form for categories.
If you set this all up, rails will handle the creation of the category when the post is created. Then you will be able to call category.posts to get all the posts with that category and you can call post.categories to get all the categories assigned to the post.
Assigning a Post to a Category can be accomplished in the create method of your PostsController. You are already passing the category_id to the controller via the params.
def create
#post = current_user.posts.new(post_params)
#category = Category.find(params[:category_id])
if #post.save && (#category.posts << #post)
redirect_to #post
else
render :new
end
end
When you are trying to show a post in a view, you should be able to access that category directly.
<%= post.category.name %>
If you allow some posts to be created without a category, you can simply not show anything, or show a "No Category" message.
# Don't show anything if the post doesn't belong to a category
<%= post.category.name if post.category.present? %>
# Show a "No Categories" message (this uses the ternary operator)
<%= post.category.present? ? post.category.name : "No Category" %>
in my search.html.haml, I want the user have the ability to click on the teacher name and it will lead them to the teacher show page. However, it also requires me to have the school_id because a teacher belongs to a school, and a school has many teachers. Now, I am wondering if there is a way for me to a the school_id to the path without breaking the application. The error that rails is throwing at me now is:
No route matches {:action=>"show", :controller=>"teachers", :id=>"1",
:school_id=>nil} missing required keys: [:school_id]
Here are my files:
search.html.haml:
.text-center
/ No search results announcement/notification
- if #teachers.blank?
%h2 Xin lỗi, hệ thống chúng tôi không có thông tin về giảng viên mà bạn muốn tìm.
- else
- #teachers.each do |teacher|
%h2= link_to teacher.fullName, school_teacher_path(#school, teacher)
#note
%em
Khoa #{teacher.department}, trường #{teacher.school.name}
teachers_controller.rb:
class TeachersController < ApplicationController
before_action :find_school, except: [:welcome, :search]
before_action :find_teacher, only: [:show, :edit, :update, :destroy]
def welcome
end
def show
end
def search
if params[:search].present?
#teachers = Teacher.search(params[:search], fields: [:fullName])
else
#teachers = nil
end
end
def new
#teacher = #school.teachers.build
end
def create
#teacher = #school.teachers.create(teacher_params)
#teacher.save
redirect_to(#school)
end
def edit
end
def update
#teacher.update(teacher_params)
redirect_to(#school)
end
private
def find_school
#school = School.find(params[:school_id])
end
def find_teacher
#teacher = Teacher.find(params[:id])
end
def teacher_params
params.require(:teacher).permit(:firstName, :lastName, :middleName, :department, :school_id, :fullName)
end
end
teacher.rb:
class Teacher < ActiveRecord::Base
belongs_to :school
has_many :ratings
searchkick
def name
"#{lastName} #{middleName} #{firstName}"
end
def to_s
name
end
end
school.rb:
class School < ActiveRecord::Base
has_many :teachers, dependent: :destroy
# searchkick
end
routes.rb:
Rails.application.routes.draw do
devise_for :users
resources :schools do
# collection do
# get 'search'
# end
resources :teachers do
collection do
get 'search'
end
end
end
resources :teachers do
collection do
get 'search'
end
resources :ratings
end
root 'teachers#welcome'
end
school_teacher_path is called with a #school that is nil since find_school is not used for search. You probably want to replace #school with teacher.school: school_teacher_path(teacher.school, teacher).
I am trying to follow this video railscast #364 but I am having a lot of trouble with my nested routes. When I use this code:
<%= link_to "up", vote_movie_review_path(#movie, #reviews, type: "up"), method: "post" %>
I get this error when I select up vote:
ActiveRecord::RecordNotFound in ReviewsController#vote
Couldn't find Review with 'id'=# <Review::ActiveRecord_Relation:0x007f0358c1e550>
This is my route:
vote_movie_review POST /movies/:movie_id/reviews/:id/vote(.:format) genre_linkers#vote
I created another model that was not nested using this code:
<%= link_to "up", vote_movie_path(movie, type: "up"), method: "post" %>
and that one worked. So I am thinking it has to be something wrong with my path or how I am calling the objects. I have spent almost all day working on this, I really need help.
review_controller.rb
class ReviewsController < ApplicationController
before_action :set_review, only: [:show, :edit, :update, :destroy]
before_action :set_movie
before_action :authenticate_user!
respond_to :html
def index
#reviews = Review.all
respond_with(#reviews)
end
def show
end
def vote
value = params[:type] == "up" ? 1 : -1
#review = Review.find(params[:id])
#review.add_evaluation(:vote, value, current_user)
redirect_to :back, notice: "thanks for the vote"
end
def new
#review = Review.new
respond_with(#review)
end
def edit
end
def create
#review = Review.new(review_params)
#review.user_id = current_user.id
#review.movie_id = #movie.id
if #review.save
redirect_to #movie
else
render 'new'
end
end
def update
#review.update(review_params)
respond_with(#review)
end
def destroy
#review.destroy
respond_with(#review)
end
private
def set_review
#review = Review.find(params[:id])
end
def set_movie
#movie = Movie.find(params[:movie_id])
end
def review_params
params.require(:review).permit(:genre, :description, :vote)
end
end
routes.rb
Rails.application.routes.draw do
devise_for :users
resources :movies do
resources :reviews do
member { post :vote }
end
end
root 'movies#index'
end
and the model
review.rb
class Review < ActiveRecord::Base
belongs_to :user
belongs_to :movie
has_reputation :votes, source: :user, aggregated_by: :sum
end
The culprit is this part of your link_to: vote_movie_review_path(#movie, #reviews, type: "up"). #reviews is an ActiveRecord::Relation and not a Review record, hence no record with an ID can be found.