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).
Related
I've got two models with simple belongs_to has_many relation, as follows:
class Property < ApplicationRecord
belongs_to :portfolio, optional: true
end
class Portfolio < ApplicationRecord
has_many :properties, dependent: :nullify
end
Which were created by migrations:
class CreateProperties < ActiveRecord::Migration[6.0]
def change
create_table :properties do |t|
t.string :name, null: false
t.string :status, null: false
t.references :portfolio, foreign_key: true
t.timestamps
end
end
end
class CreatePortfolios < ActiveRecord::Migration[6.0]
def change
create_table :portfolios do |t|
t.string :name, null: false
t.timestamps
end
end
end
When I want to create new Property with portfolio_id: 1 which doesn't exist I'm getting an error:
PG::ForeignKeyViolation: ERROR: insert or update on table "properties" violates foreign key constraint "fk_rails_760fb8258a" DETAIL: Key (portfolio_id)=(1) is not present in table "portfolios".
How to handle such error and display to user information such as "portfolio_id doesn't exist" ?
Create action is pretty standard:
property_controller.rb
def create
#property = Property.new(property_params)
respond_to do |format|
if #property.save
format.html { redirect_to #property, notice: 'Property was successfully created.' }
format.json { render :show, status: :created, location: #property }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #property.errors, status: :unprocessable_entity }
end
end
end
The error makes sense, since you're trying to create a property with a portfolio_id that doesn't exist. Since you added the optional: true to belongs_to :portfolio in the Property class, you removed the validation that normally comes with the belongs_to.
The best way of avoiding that would be to display a dropwdown in the form for a new portfolio that contains all the possible properties. That would also be better in terms of UX because the user would not have to remember the id of a property.
I want to make sure that when I create a record in the front end, the user id of the user who created it is automatically assigned to this record. What should I do in the backend if I want the id of the authorized user to be automatically assigned to the record when creating the record? For authorization I use gem 'devise_token_auth'.
notebooks_controller.rb:
class NotebooksController < ApplicationController
before_action :set_notebook, only: [:show, :update, :destroy]
def index
#notebooks = Notebook.all
render json: #notebooks
end
def show
render json: #notebook
end
def create
#notebook = Notebook.new(notebooks_params)
if #notebook.save
render json: #notebook, status: :created, location: #notebook
else
render json: #notebook.errors, status: :unprocessable_entity
end
end
def update
if #notebook.update(notebooks_params)
render json: #notebook
else
render json: #notebook.errors, status: :unprocessable_entity
end
end
def destroy
#spr_contract_solution.destroy
end
private
def set_notebook
#notebook = Notebook.find(params[:id])
end
def notebooks_params
params.require(:notebook).permit!
end
end
notebook.rb:
class Notebook < ApplicationRecord
belongs_to :user
end
...._create_notebooks.rb
class CreateNotebooks < ActiveRecord::Migration[5.1]
def change
create_table :notebooks do |t|
t.string :title
t.text :description
t.boolean :is_active
t.references :user, foreign_key: true
t.timestamps
end
end
end
First, #Subash is right, you need to pass the list of parameters to the permit method in notebook_params (note that maybe you would want to use permit instead of permit!), for example:
params.require(:notebook).permit :name, :text, :any_other_attribute_you_are_saving
Then, to answer your question, you could do something like this in the create action:
#notebook = Notebook.new(notebooks_params)
#notebook.user = current_user #Assuming you have this method available
Assuming you have has_many :notebooks in your user model, this is a popular idiom for doing what you want:
#notebook = current_user.notebooks.build(notebook_params)
add
#notebook.user = current_user
after
#notebook = Notebook.new(notebooks_params)
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.
After adding new column events_count to table users, I get this error:
SQLite3::SQLException: no such column: events_count: UPDATE "users" SET "events_count" = COALESCE("events_count", 0) + 1 WHERE "users"."id" = 2
This is extracted source with a line with bug:
#event.user_id = current_user.id
respond_to do |format|
**if #event.save**
format.html { redirect_to #event, notice: 'Event was successfully created.' }
format.json { render :show, status: :created, location: #event }
else
This is my users table:
create_table "users", force: true do |t|
.
.
.
.
t.integer "events_count", default: 0
end
This is html with ranking from users_path:
<tr>
<% User.all.each do |user| %>
<td> <%= user.name %></td>
<td> <%= user.events_count %></br></td>
<% end %>
</tr>
This is Event model:
class Event < ActiveRecord::Base
acts_as_commontable
mount_uploader :picture, PictureUploader
acts_as_votable
belongs_to :user, dependent: :destroy,counter_cache: true
end
Anyone know what may be wrong?
EDIT:
This is migration file:
class AddEventsCountToUsers < ActiveRecord::Migration
def change
add_column :users, :events_count, :integer, :default => 0
end
end
This is Event controller:
# POST /events
# POST /events.json
def create
#event = Event.new(event_params)
#event.user_id = current_user.id
respond_to do |format|
if #event.save
format.html { redirect_to #event, notice: 'Event was successfully created.' }
format.json { render :show, status: :created, location: #event }
else
format.html { render :new }
format.json { render json: #event.errors, status: :unprocessable_entity }
end
end
end
# Never trust parameters from the scary internet, only allow the white list through.
def event_params
params.require(:event).permit(:title, :description, :picture, :start_date, :start_time, :end_time, :location, :user_id, :city)
end
end
Seems like you just added event_counts instead of events_count that to an already existing create_users.rb migration file.
you have to perform a query which generates a migration file for an extra column events_count
rails g migration AddEventsCountToUsers events_count:integer
Do rake db:migrate after that
OR
Do rake db:rollback,add that column in the create_users.rb migration file and do rake db:migrate
As mentioned in the comments,try running rake db:migrate:up VERSION=20140511122817
Edit user table as:
create_table "users", force: true do |t|
.
.
.
.
t.integer :events_count, default: 0
end
And run these commands:-
rake db:drop
rake db:create
rake db:migrate
Note :- It will delete all data from your datasase
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.