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.
Related
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 !
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 have a simple has_many, belongs_to association.
class Actor < ActiveRecord::Base
belongs_to :movie
end
and
class Movie < ActiveRecord::Base
has_many :actors, dependent: :destroy
after_save :fill_actors_table
validates_presence_of :title
def fill_actors_table
movie_list = Imdb::Search.new("Lion King")
new_movie = movie_list.movies.first
id = new_movie.id
i = Imdb::Movie.new("#{id}")
i.cast_members.each do |actor_name|
actor_image = Google::Search::Image.new(:query => actor_name).first
actor_image_url = actor_image.uri
Actor.create(:name => actor_name, :file => actor_image_url)
end
end
My schema looks like this:
ActiveRecord::Schema.define(version: 20150821182841) do
create_table "actors", force: true do |t|
t.string "name"
t.string "file"
t.integer "actor_id", limit: 255
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "movies", force: true do |t|
t.string "title"
t.datetime "created_at"
t.datetime "updated_at"
end
end
But I keep getting an error
SQLite3::SQLException: no such column: actors.movie_id: SELECT "actors".* FROM "actors" WHERE "actors"."movie_id" = ?
I don't use movie_id anywhere!!!
Movie Controller Code:
class MoviesController < ApplicationController
before_action :set_movie, only: [:show, :edit, :update, :destroy]
# GET /movies
# GET /movies.json
def index
#movies = Movie.all
end
# GET /movies/1
# GET /movies/1.json
def show
end
# GET /movies/new
def new
#movie = Movie.new
end
# GET /movies/1/edit
def edit
end
# POST /movies
# POST /movies.json
def create
#movie = Movie.find_or_create_by(movie_params)
respond_to do |format|
if #movie.save
format.html { redirect_to #movie, notice: 'Movie was successfully created.' }
format.json { render :show, status: :created, location: #movie }
else
format.html { render :new }
format.json { render json: #movie.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /movies/1
# PATCH/PUT /movies/1.json
def update
respond_to do |format|
if #movie.update(movie_params)
format.html { redirect_to #movie, notice: 'Movie was successfully updated.' }
format.json { render :show, status: :ok, location: #movie }
else
format.html { render :edit }
format.json { render json: #movie.errors, status: :unprocessable_entity }
end
end
end
# DELETE /movies/1
# DELETE /movies/1.json
def destroy
#movie.destroy
respond_to do |format|
format.html { redirect_to movies_url, notice: 'Movie was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_movie
#movie = Movie.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def movie_params
params.require(:movie).permit(:title)
end
end
Actors controller was just generated and really is the same as the movie controller for the most part.
What I'm trying to accomplish:
A movie is searched. The movie name is saved in the movie database. Then it pulls a list of actors in the movie using the imdb gem and searches for their images using the google-search gem. The image url's and actor names are saved in the actor database.
I have noticed that when I put in movies, it sometimes seems to list the actors names twice (as if there are two for loops). I can't figure out where I have code that could possibly make it run twice.
This is really the only code I've written in the whole project other than a basic form.
You need the foreign key in the model with the belongs_to.
When you use:
belongs_to :some_model
rails assumes :some_model_key is in the model. You have no :movie_id in your actors model, so when you try to reference a movie's actors rails looks for the :movie_id in your actor model and can't find it. You can add this column with an active migration.
I have a one-to-many association between 2 resources: Discovery and Matter
class Discovery < ActiveRecord::Base
belongs_to :matter
end
class Matter < ActiveRecord::Base
has_many :discoveries
end
My routes file has this:
resources :matters do
resources :discoveries
end
My migration files look like:
class CreateDiscoveries < ActiveRecord::Migration
def change
create_table :discoveries do |t|
t.string :aws_url
t.string :upload_file_path
t.attachment :upload
t.integer :matter_id
t.string :direct_upload_url
t.boolean :processed
t.timestamps
end
end
end
class AddMatterIdToDiscoveries < ActiveRecord::Migration
def change
add_index :discoveries, :matter_id
add_index :discoveries, :processed
end
end
discoveries_controller.rb
def create
#matter = Matter.find(params[:matter_id])
if(params[:url])
#discovery = Discovery.new
render "new" and return
end
if(params[:discovery][:upload_file_path])
#discovery = Discovery.new(discovery_params)
respond_to do |format|
if #discovery.save
#discovery.matter = current_user.matters.find(params[:matter_id])
format.html { render action: :show, notice: 'Discovery was successfully created.' } # matter_url(#discovery.matter_id)
format.json { render action: 'show', status: :created, location: #discovery }
else
format.html { render action: 'new' }
format.json { render json: #discovery.errors, status: :unprocessable_entity }
end
# redirect_to new_document and return
end
else
#discovery = Discovery.new
render action: 'new', notice: "No file"
end
end
When I create a new discovery in the matters model matters/3/discoveries/new the discovery gets created, but in the console, I thought I should be able to access Discovery.last.matter, but instead I get the error NoMethodError: undefined method 'matter' for #<Discovery:0x0000000495dc98>
How would I go about showing the matter that the discovery belongs to? Thanks
Call reload! in the console after changing your models (schema changes, running migrations, adding methods).
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