ActiveRecord::StatementInvalid in EventsController#create - ruby-on-rails

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

Related

how update has_and_belongs_to_many table on update activeRecord

I'm having trouble doing a has_and_belongs_to_many, my data is structured as follows
# app/models/student.rb
class Student < ApplicationRecord
belongs_to :city
belongs_to :degree
has_and_belongs_to_many :services, optional: true
end
# app/models/service.rb
class Service < ApplicationRecord
has_and_belongs_to_many :student, optional: true
belongs_to :vendor
belongs_to :degree, optional: true
end
in my database schema i have this table and the tables of student and service.
create_table "services_students", id: false, force: :cascade do |t|
t.integer "service_id", null: false
t.integer "student_id", null: false
end
what happens is for a Student to be associated with a Service, I needed to add some lines in services_controller.create()
# POST /services or /services.json
def create
#service = Service.new(service_params)
for student in params[:service][:student]
if student != ""
#service.student << Student.find(student)
end
end
respond_to do |format|
if #service.save
format.html { redirect_to service_url(#service), notice: "Service was successfully created." }
format.json { render :show, status: :created, location: #service }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #service.errors, status: :unprocessable_entity }
end
end
end
this way the tables save the information correctly. however, in the update() function, when saving the record, the service_students table records are duplicated instead of being updated.
in services_controller i have set the permit params as this:
# service_controller.rb
# Only allow a list of trusted parameters through.
def service_params
params.require(:service).permit(:student, :vendor_id, :degree_id, :category, :description)
end
and in my form is like this:
# .... begin of form ...
<%= form.label :student, "Aluno(s)" %>
<%= form.collection_check_boxes :student, Student.all, :id, :name do |b|
b.label(class:"w-full ") { b.check_box(class:"rounded", checked: #service.student.ids.include?(b.object.id)) + b.text }
# .... more fields of form ....
I'm not understanding what I'm doing wrong. shouldn't the update function, and even create(), handle this without having to add more code?
I tried to follow some tutorials on the internet, and I realized that the activeRecord should generate the attribute students_ids or students to register the association correctly, but I didn't understand exactly why this happens or why in my model it is referred to as student. (maybe something is wrong)
>> rails console
service = Service.find(1) # get the Service with id: 1
student1 = Student.find(1) # get the Student with id: 1
student2 = Student.find(2) # get the Student with id: 2
service.students << student1 # error
service.student << student1 # works
service.students #error #method missing
service.student # display all students relationship
is this supposed to happen?
The assocation should have a plural name:
class Service < ApplicationRecord
has_and_belongs_to_many :students # this should be plural!
belongs_to :vendor
belongs_to :degree, optional: true
end
Use the students_ids method generated by has_and_belongs_to_many :students with your input:
<%= form.collection_check_boxes :student_ids, Student.all, :id, :name do |b| %>
<%= b.label(class:"w-full") { b.check_box(class:"rounded") + b.text } %>
<% end %>
And you need to whitelist an array of ids:
def service_params
params.require(:service)
.permit(
:vendor_id, :degree_id,
:category, :description,
student_ids: [] # permits an array of values
)
end
And just get rid of the cruft:
def create
#service = Service.new(service_params)
respond_to do |format|
if #service.save
format.html { redirect_to #service, notice: "Service was successfully created." }
format.json { render :show, status: :created, location: #service }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #service.errors, status: :unprocessable_entity }
end
end
end
The students_ids= method which is also created by has_and_belongs_to_many :students will automatically add/delete the rows in the join table.

No such column for dependent :destroy on has_many, belongs_to relationship

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.

Multi-uploads with Carrierwave on Rails 4.2 using nested attributes JSON/Array type

I'm trying to figure out multi-uploads with CarrierWave and being able to save it from a different Controller and Model through accepts_nested_attributes_for :car_images, reject_if: :all_blank, allow_destroy: true
I'm using CarrierWave and my CarImage model contains a JSON type column for the image.
When creating a new car post CarsController#New I want to be able to:
Write title (working)
Write description (working)
Upload multiple images through nested forms (working)
I get the following error message when trying to save a new Car with images attached:
Unpermitted parameter: images
The params:
Started POST "/cars" for 127.0.0.1 at 2015-08-20 22:04:19 +1000
Processing by CarsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"GEAGEAKQw3foK7/1+kGMhTVArqRaC8gHaHjHAtef0zmJDr2i5U9TictQ9kj3A==", "car"=>{"title"=>"Ford", "description"=>"Mustang", "car_images_attributes"=>{"0"=>{"images"=>[#<ActionDispatch::Http::UploadedFile:0x007fbec0dfa5a8 #tempfile=#<Tempfile:/var/folders/r0/24wrt39d1kl37mmymjjmmxy45000gn/T/RackMultipart20150820-12757-1e4egob.jpg>, #original_filename="ford-mustang-front.jpg", #content_type="image/jpg", #headers="Content-Disposition: form-data; name=\"car[car_images_attributes][0][images][]\"; filename=\"ford-mustang-front.jpg\"\r\nContent-Type: image/jpg\r\n">, #<ActionDispatch::Http::UploadedFile:0x007fbec0dfa508 #tempfile=#<Tempfile:/var/folders/r0/24wrt39d1kl37mmymjjmmxy45000gn/T/RackMultipart20150820-12757-6pckqd.png>, #original_filename="ford-mustang-back.jpg", #content_type="image/png", #headers="Content-Disposition: form-data; name=\"car[car_images_attributes][0][images][]\"; filename=\"ford-mustang-back.jpg\"\r\nContent-Type: image/jpg\r\n">]}}}, "commit"=>"Create Car"}
I'm not sure if it's to do with the form, but when saving multiple files as an Array should it have unique indexes? The params log looks like it's saving all the images in the first index: car[car_images_attributes][0][images][]\
My CarsController the permits the following params:
def car_params
params.require(:car).permit(:title, :description,
car_images_attributes: [:id, :car_id, :image])
end
The car_images_attributes permits the :image attribute which is a JSON/Array type.
Any insight is much appreciated.
Car Model
# == Schema Information
#
# Table name: cars
#
# id :integer not null, primary key
# title :string default(""), not null
# description :text default("")
# price :float default(0.0)
# created_at :datetime not null
# updated_at :datetime not null
class Car < ActiveRecord::Base
has_many :car_photos
accepts_nested_attributes_for :car_images, reject_if: :all_blank, allow_destroy: true
end
Car Image Model
# == Schema Information
#
# Table name: car_images
#
# id :integer not null, primary key
# image :json default({}), not null
# title :string default(""), not null
# car_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
class CarImages < ActiveRecord::Base
belongs_to :car
mount_uploader :image, ImageUploader
end
Car Controller
class CarsController < ApplicationController
before_action :set_car, only: [:show, :edit, :update, :destroy]
def show
end
def new
#car = Car.new
#car.car_images.build
end
def edit
end
def create
#car = Car.new(car_params)
respond_to do |format|
if #car.save
format.html { redirect_to #car, notice: 'Car was successfully created.' }
format.json { render :show, status: :created, location: #car }
else
#car.car_images.build # ensures car_image form object exists
format.html { render :new }
format.json { render json: #car.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #car.update(car_params)
format.html { redirect_to #car, notice: 'Car was successfully updated.' }
format.json { render :show, status: :created, location: #car }
else
format.html { render :new }
format.json { render json: #car.errors, status: :unprocessable_entity }
end
end
end
def destroy
#car.destroy
respond_to do |format|
format.html { redirect_to root_path, notice: 'Car was successfully destroyed.'}
format.json { head :no_content }
end
end
private
def set_car
#car = Car.find_by_id(params[:id])
end
def car_params
params.require(:car).permit(:title, :description, car_images_attributes: [:id, :car_id, :images])
end
end
Car Form
<%= simple_form_for #car, html: { multipart: true } do |f| %>
<%= f.input :title %>
<%= f.input :description, as: :text %>
<%= f.simple_fields_for :car_images do |image| %>
<% if image.object.new_record? %>
<%= image.input :images, as: :file, required: false, error: false, input_html: { multiple: true } %>
<% end %>
<% end %>
<%= f.button :submit %>
<% end %>
Any insights is much appreciated.
I was thinking of iterating through the params[:car_images]['image'] and creating a CarImage record, but i thought this might not be the best way, and would want to be able to add a Car record without images, and this would fail if it doesn't have an image attached unless extra checks (nil) is done.
Update
I've tried DB column types JSON and TEXT (as an array) but still have the problems. If I change it as a plain STRING it works but it's not a collection of photos.

Accessing one-to-many association from console

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).

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