Add favorite button ruby on rails - ruby-on-rails

So, i want to add a favorite button in my view show internship, but i get this error : {:favorite_internship=>["must exist"]}
I don't known how to tell rails that the id of the show view internship is the favorite_internship_id
I've tried this in internship controller but it doesn't work
#favorite.favorite_internship_id = #internship.id
First, the table Favorite, Internship has the class_name 'favorite_internship' and User has the class_name 'favorite_user'
create_table "favorites", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "favorite_user_id"
t.bigint "favorite_internship_id"
t.index ["favorite_internship_id"], name: "index_favorites_on_favorite_internship_id"
t.index ["favorite_user_id"], name: "index_favorites_on_favorite_user_id"
end
Favorite model
class Favorite < ApplicationRecord
belongs_to :favorite_user, class_name: "User"
belongs_to :favorite_internship, class_name: "Internship"
end
Internship model
class Internship < ApplicationRecord
has_many :favorites, foreign_key: "favorite_internship_id"
has_many :favorite_users, foreign_key: "favorite_user_id", class_name: "User", through: :favorites
end
Favorite Controller
class FavoritesController < ApplicationController
def new
#favorite = Favorite.new
end
def create
#favorite = Favorite.new(favorite_internship_id: params[:favorite_internship_id], favorite_user_id: params[:favorite_user_id])
#favorite.favorite_user = current_user
respond_to do |format|
if #favorite.save
format.html { redirect_back fallback_location: root_path, notice: 'Favorite was successfully created.' }
format.json { render :show, status: :created, location: #favorite }
else
format.html { redirect_back fallback_location: root_path, notice: "Le favoris n'a pas pu être créé : #{#favorite.errors.messages}" }
format.json { render json: #favorite.errors, status: :unprocessable_entity }
end
end
end
end
So the favorite button is in the show internship. Here's the internship controller :
class InternshipsController < ApplicationController
def show
#reviews_of_internship = #internship.reviews.order(created_at: :desc).paginate(page: params[:page], per_page: 4)
#review = Review.new
#favorite = Favorite.new
#favorite.favorite_internship_id = #internship.id
end
end
Routes
resources :favorites
resources :internships do
resources :reviews, only: [:new, :create, :edit, :update, :destroy]
resources :favorites, only: [:new, :create, :destroy]
end
The create favorite route is :
internship_favorites POST /internships/:internship_id/favorites(.:format) favorites#create
I have a button 'Favorite' in the view to click, so that the internship is favored
<%= button_to "Favorite", internship_favorites_path(#internship), method: :post %>
This is where i get the error '{:favorite_internship=>["must exist"]}'.
So if you have an advice on this, on how i should do it. Is the button a good idea or should i do it otherwise ?

you have favorite_internship model?
if yes than you have to add in you model that belongs to favorite
belongs_to :favorite, optional: true

Problem solved ! I didn't put this code :
#favorite.favorite_internship_id = #internship.id
In the right controller it should be in controller Favorite, in def #create, sorry i'm a beginner, anyway it woooooorks !!!
Also, i had a better advice which was to to that with the favorite params (in favorite controller #create):
#favorite = Favorite.new(favorite_internship_id: params[:internship_id], favorite_user_id: current_user.id)
I removed the other line, it works fine !

Related

How to associate a subscriber to an event

I'm trying to make that a subscriber, sub to an certain event
with the following url per example:
http://localhost:3001/events/1/subscribers/new
but I don't know how to associate event_id when creating a new subscriber
for the moment i'm getting this error:
Couldn't find Event with 'id'=
in the routes:
resources :events do
resources :subscribers #url/events/:events_id/subscribers/new
end
resources :events
root 'events#index'
in the subscribers controller:
def show
end
# GET /subscribers/new
def new
#puts "Look for me in console\n"
#puts params.inspect
#event = Event.find(params[:events_id])
#subscriber = #event.Subscriber.new
end
# GET /subscribers/1/edit
def edit
end
# POST /subscribers
# POST /subscribers.json
def create
#event = Event.find(params[:order_id])
#subscriber = #event.Subscriber.new order_params
##subscriber = Subscriber.new(subscriber_params)
respond_to do |format|
if #subscriber.save
SubsMailer.new_subscriber(#subscriber).deliver
format.html { redirect_to #subscriber, notice: 'Subscriber was successfully created.' }
format.json { render :show, status: :created, location: #subscriber }
else
format.html { render :new }
format.json { render json: #subscriber.errors, status: :unprocessable_entity }
end
end
end
in the new.html.erb:
<h1>New Subscriber</h1>
<%= render 'form', subscriber: #subscriber %>
<%= link_to 'Back', subscribers_path %>
model association:
event.rb:
class Event < ApplicationRecord
has_many :subscribers, dependent: :destroy
end
subscriber.rb:
class Subscriber < ApplicationRecord
belongs_to :event
validates :email, presence: true,
format: /\A\S+#\S+\z/,
uniqueness: { case_sensitive: false }
end
Well, I think this documentation will help you to understand what you need to do.
If briefly at first you need to change your models. You could have many to many for Event -> Subscriber association or one to many. One to many is the simplest to show so you need to add this to your Subscriber model:
belongs_to :event
And this to your Event model:
has_many :subscribers
Add new migration:
def change
remove_column :subscribers, :events_id
remove_column :subscribers, 'Event_id'
add_column :subscribers, :event_id, :integer
end
Then in your controller, you should change method calls, as Subscriber is a class, not the method.
def new
#event = Event.find(params[:event_id])
#subscriber = #event.subscribers.build
end
And you should be sure that in your database you have Event with this id.
To check it you can try to debug your controller code:
def new
puts "Event ids: " + Event.all.map(&:id).inspect
#event = Event.find(params[:event_id])
#subscriber = #event.subscribers.build
end
In your logs you should have something like:
Event ids: [1]
I think you just have a typo in your new method. You call params[:eventS_id] when it should be params[:event_id]. Also you don't properly reference your association. it should be event.subscribers.new:
def new
#puts "Look for me in console\n"
#puts params.inspect
#event = Event.find(params[:event_id])
#subscriber = #event.subscribers.build
end
Migration:
def up
change_table :subscribers do |t|
t.remove :Event_id
t.references :event
end
end
def down
change_table :subscribers do |t|
t.remove :event_id
t.add :Event_id, :integer
end
end
Keep me posted whether this helps and if you have any additional issues

Rails, How to show all product by category search feature?

Now I want to add some add search feature to my project. I have 2 table about product and category, then i'm using one to many relation. I get stuck when i want to search my product by their categories. Here my code:
products_controller.rb:
def index
#product = Product.all
render json: #product, status: :ok
end
def search
#category = Category.find(params[:category_id])
#product = #category.products
render json: #product, status: :ok
end
def show
render json: #product, status: :ok
end
routes.rb
Rails.application.routes.draw do
namespace :v1 do
resources :products
resources :categories
post 'products/search', to: "products#search"
get 'products/search', to: "products#search"
end
end
model category.rb
class Category < ApplicationRecord
has_many :products
end
model product.rb
class Product < ApplicationRecord
belongs_to :category
end
my product table field
t.integer :category_id
t.string :product_name
t.string :company
t.text :description
t.string :logo_img
t.string :web_link
my table category field
t.string :category_name
t.string :status
How should it work for category show all their products?
Thanks for your help
add your categories_controller.rb like following
categories_controller.rb
def show
category = Category.find(params[:id])
render json: category.products, status: :ok
end
end
and visit /categories/:id url

How do I param the Controller Favorite Create method to have an index#view

I want to create a polymorphic model to favorite each objects I want to create to stock in my user page.
I am developing a web app to learn japanese and we can favorite different types of cards as kanas or kanjis and sentences.
So there are 3 objects and soon more to favorite.
I migrated a table which names Favorite :
create_table "favorites", force: :cascade do |t|
t.integer "user_id"
t.integer "favoritable_id"
t.string "favoritable_type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Here is the Favorite model belongs_to
class Favorite < ActiveRecord::Base
belongs_to :favoritable, polymorphic: true
belongs_to :user
end
Here are the Cards model has_many
class Symbole < ActiveRecord::Base
accepts_nested_attributes_for :kanji_attribute, :allow_destroy => true
has_many :sentence_symboles, :class_name => "SentenceSymbole", :foreign_key => "symbole_id"
has_many :favorites, as: :favoritable
end
and I added in sentence model too
class Sentence < ActiveRecord::Base
include Authority::Abilities
has_many :sentence_symboles, :class_name => "SentenceSymbole", :foreign_key => "sentence_id", dependent: :destroy
has_many :favorites, as: :favoritable
end
Now here is the Favorite controller and I don't really know how to write the create method. Here is the Controller I do:
class FavoritesController < ApplicationController
def index
#favorites = Favorite.where(user: current_user)
end
def create
#Favorite.create(user_id: User.last.id, favoritable_id: Symbole.last.id, favoritable_type:"Symbole")
#favorite = current_user.favoritable.favorites.create(symbole: #symbole, sentence: #sentence).first
if #favorite.present?
#favorite.destroy
else
#favorite = current_user.favorites.new(symbole: #symbole, sentence: #sentence)
if not #symbole.favorites.where(user: current_user).take
#sentence.favorites.where(user: current_user).take
#favorite.save
end
end
# redirect_to favs_path
# redirect_to :back
respond_to do |format|
format.js { render :ajax_update_favs }
end
end
def destroy
#favorite = Favorite.find(params[:id])
#favorite.destroy
redirect_to :back
end
end
Please could someone give me the right way to favorite all object I want and add in an favorite index#view.
Thank you for your help.
I think my question is simple but no. How to favorite each object I want with the def Create controller what is the best method?
I do that
def create
#Favorite.create(user_id: User.last.id, favoritable_id: Symbole.last.id, favoritable_type:"Symbole")
#favorite = #favoritable.favorites.build(favorite_params)
#favorite.user = current_user
#favorite.save
respond_to do |format|
format.js { render :ajax_update_favorites }
end
end
Not sure I understood the problem entirely. It looks like you're overcomplicating favoritesController#create. If a record only should be favorited once, you should add a uniqueness validation in the Favorite model.
Assuming that you have your user model set up like
class User < ActiveRecord::Base
has_many :favorites
# Rest..
end
def create
#favorite = current_user.favorites.create(favorite_params)
# This will create a new Favorite with user_id: current_user.id, favoritable_type: "Symbole", favoritable_id: 1337
# Is this the desired behaviour?
respond_to do |format|
format.js { render :ajax_update_favs }
end
end
private
def favorite_params
params.require(:favorite).permit(:favoritable_type, :favoritable_id)
end
If this is called from javascript with jquery pass the type and id that you wan't to favorite.
$.post( "/favorites", {
favorites: {
favoritable_type: "Symbole",
favoritable_id: 1337
}
});

Create a Post_category for a Post a choose my post with collection post_category

I created a post_category table to add a category to specifics posts.
For example I created post_categories as Countries, Like Japan or China. And I want to create post which are come from culture or mode from countries like Japan or China. I focused only on post_categories as countries for now and below is the code I did.
I created this PostCategory, here are the migration and model
create_table "post_categories", force: :cascade do |t|
t.string "name"
t.string "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
class PostCategory < ActiveRecord::Base
has_many :posts, dependent: :destroy
NAMES = ["Japon", "Chine", "Corée du Sud", "Moyen Orient", "Indien"]
validates :name, inclusion: { in: PostCategory::NAMES, allow_nil: false }
end
And I created a Post with the PostCategory foreign key, here are the migration and model
create_table "posts", force: :cascade do |t|
t.string "cover"
t.string "subtitle"
t.string "title"
t.text "introduction"
t.text "body"
t.text "conclusion"
t.string "tag"
t.string "source"
t.string "link"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "post_category_id"
end
class Post < ActiveRecord::Base
belongs_to :user
belongs_to :post_category, dependent: :destroy
TAGS = ["Design", "Mode", "Tendance", "Life-Style", "Tradition", "Gastronomie", "Insolite", "Technologie"]
validates :tag, inclusion: { in: Post::TAGS, allow_nil: false }
mount_uploader :cover, ImageUploader
end
I want to create a category with a simple form collection and I want i will be displayed on the post show#view
Here is the post_categories controller
class PostCategoriesController < ApplicationController
# before_action :set_post_category, only: [:show, :new, :create, :destroy]
def show
#post_category = PostCategory.find(params[:id])
end
def index
#post_categories = PostCategory.all
end
def create
#post_category = post_categories.new(post_category_params)
if #post_category.save
redirect_to #post
else
render 'post_categories/show'
end
end
def new
#post_category = PostCategory.new
end
def edit
end
def update
end
def destroy
#post_category = PostCategory.find(params[:id])
#post_category.destroy
redirect_to post_path(#post)
end
private
# def set_post
# #post = Post.find(params[:post_id])
# end
def find_post_category
#post_category = PostCategory.find(params[:id])
end
def post_category_params
params.require(:post_category).permit(:name, :description)
end
end
And here is the posts controller
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 = #post_category.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_post_category
#post_category = PostCategory.find(params[:post_category_id])
end
def post_params
params.require(:post).permit(:title, :subtitle, :introduction, :body, :cover, :tag, :post_category_id)
end
end
I don't know what views could I do create and how calling the post new#view because I configured my routes like that, and I need a post_category_id.
resources :post_categories do
resources :posts
end
That's I have to use this following path
post_category_posts GET /post_categories/:post_category_id/posts(.:format) posts#index
POST /post_categories/:post_category_id/posts(.:format) posts#create
new_post_category_post GET /post_categories/:post_category_id/posts/new(.:format) posts#new
edit_post_category_post GET /post_categories/:post_category_id/posts/:id/edit(.:format) posts#edit
post_category_post GET /post_categories/:post_category_id/posts/:id(.:format) posts#show
PATCH /post_categories/:post_category_id/posts/:id(.:format) posts#update
PUT /post_categories/:post_category_id/posts/:id(.:format) posts#update
DELETE /post_categories/:post_category_id/posts/:id(.:format) posts#destroy
post_categories GET /post_categories(.:format) post_categories#index
POST /post_categories(.:format) post_categories#create
new_post_category GET /post_categories/new(.:format) post_categories#new
edit_post_category GET /post_categories/:id/edit(.:format) post_categories#edit
post_category GET /post_categories/:id(.:format) post_categories#show
PATCH /post_categories/:id(.:format) post_categories#update
PUT /post_categories/:id(.:format) post_categories#update
DELETE /post_categories/:id(.:format) post_categories#destroy
I want to add the category on my show#view post and create a multisearch access to find posts added to a specific category. Thank you for your help
The way you have setup your relations since has a very big flaw - a post can only belong to a single category since the id is stored on the posts table.
Instead you would commonly use a many to many relationship:
class Post < ActiveRecord::Base
has_many :categories, :categories
has_many :post_categories
end
class Category < ActiveRecord::Base
has_many :posts
has_many :posts, through: :categories
end
class Categorization < ActiveRecord::Base
belongs_to :post
belongs_to :category
validates_uniqueness_of :category_id, scope: :post_id
end
Here the categorizations table acts as a join table which links Post and Category - A post can have any number of categories and vice versa.
ADDED:
To create the join model and a migration to create table you would do:
rails g model Categorization post:belongs_to category:belongs_to
Using belongs to in the generator by default creates foreign keys for post_id and category_id.
You might want to add a compound uniqueness constraint in the migration as well.
def change
# ...
add_index(:categorizations, [:post_id, :category_id], unique: true)
end
Your on the right track with your CategoriesController but I would not use a nested route to create posts. Instead you might want to just use a plain old rails controller and let the user select categories via check boxes:
<%= form_for(#post) do |f| %>
<%= f.collection_check_boxes :category_ids, Category.all, :id, : name %>
<% end %>
You would then add the category_ids param to the whitelist:
def post_params
params.require(:post)
.permit(:title, :subtitle, :introduction,
:body, :cover, :tag, category_ids: []
)
end
The weird category_ids: [] syntax is because we want to allow an array of scalar values.
Querying for posts from a category by id can be done like so:
Post.joins(:categories).where(category: 1)
You can even select multiple categories by passing an array:
Post.joins(:categories).where(category: [1, 2, 3])
To hook this together from the view you would use a link (for a single category) or a form (yes forms can be used for GET) with checkboxes or selects.
Dealing with textual input is a bit trickier. A naive implementation would be:
Post.joins(:categories).where(category: { name: params[:search_query] })
However the user input would have to match exactly. There are several gems that provide search features to active record. However I would wait with the feature until you have a bit more experience as it can be tricky to implement.
See:
Rails guides: The has_many :through Association
Rails guides: Strong Parameters
Rails api: collection_check_boxes

Rails associated model id on create

I have 2 models, a sport model and a team model. The team model belongs_to :sport and the sport model has_many :teams.
Sport model:
class Sport < ActiveRecord::Base
has_many :teams
has_many :competitions
has_many :games
end
Team Model:
class Team < ActiveRecord::Base
belongs_to :sport
has_many :competition_teams
has_many :competitions, :through => :competition_teams
has_many :home_games, :foreign_key => "home_team_id", :class_name => "Game"
has_many :visiting_games, :foreign_key => "visiting_team_id", :class_name => "Game"
end
When a new team is created it must always associate with a sport. So for example if Hockey has an ID of 1, the team that is created under hockey must contain the sport ID. Below is the current schema:
create_table "sports", force: true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "teams", force: true do |t|
t.string "name"
t.integer "sport_id"
t.datetime "created_at"
t.datetime "updated_at"
end
This is the teams controller:
class TeamsController < ApplicationController
before_action :set_team, only: [:show, :edit, :update, :destroy]
# GET /games
# GET /games.json
def index
#teams = Team.all
end
# GET /games/1
# GET /games/1.json
def show
end
# GET /games/new
def new
#team = Team.new
end
# GET /games/1/edit
def edit
end
# POST /games
# POST /games.json
def create
#team = Team.new(team_params)
respond_to do |format|
if #team.save
format.html { redirect_to #team, notice: 'team was successfully created.' }
format.json { render action: 'show', status: :created, location: #team }
else
format.html { render action: 'new' }
format.json { render json: #team.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /games/1
# PATCH/PUT /games/1.json
def update
respond_to do |format|
if #team.update(team_params)
format.html { redirect_to #team, notice: 'team was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #team.errors, status: :unprocessable_entity }
end
end
end
# DELETE /games/1
# DELETE /games/1.json
def destroy
#team.destroy
respond_to do |format|
format.html { redirect_to sports_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_team
#team = Team.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def team_params
params[:team].permit(:name, :sport_id)
end
end
I tried to do the following in the routes:
resources :sports do
resources :teams
end
But get an error when trying to create a team from the the following URL: /sports/1/teams/new
The error is: undefined method `teams_path' for #<#:0x007fafb4b9b0c0>
app/views/teams/_form.html.erb where line #1 raised:
For your route setup:
resources :sports do
resources :teams
end
You will need to use new_sport_team_path which will map to sports/:sport_id/teams/:id/new.
And in your app/view/teams/_form.html.erb, since your route is sports/:sport_id/teams, your form_for declaration should be:
<%= form_for #comment, url: sport_teams_path ... %>
...
<% end %>
In this case sport_teams_path will route to /sports/:sport_id/teams with post method which will execute the create action in your TeamsController.
The form_for declaration above can also be written as:
<%= form_for([#sport, #team]) ... %>
...
<% end %>
In this case you'd need to define #sport and #team in your controller as follows:
# app/controllers/teams_controller.rb
def new
#sport = Sport.find(params[:sport_id])
#team = #sport.teams.build
...
end
For a list of routes defined in your application, you could run rake routes from within your application directory in the terminal.

Resources