How to update the users balance when a user makes a transaction? - ruby-on-rails

I am stock trying to write the code that make possible for users to update a balance every time they make a transaction.
This is a simple bartering application:
The user can either offer products for sale or buy products from other users.
The user pays with a kind of virtual money (units).
When a user clicks in Order a transaction is executed.
The Models are: User, Product and Order.
If the user orders a product ( here order=transaction) I expect that the orders price (here price=amount) will be added to the users balance:
My expectation is that this code in orders_controller could make that the amount of #price pass and adds to #balance and makes possible the update:
#user.balance = balance: (#user.balance += #order.price)
But this is not working
I have tried as well in orders_controller with this:
def balance
if #order.save
#user.balance_update!(balance: #user.balance + #order.price)
end
end
But doesnt work.
What could be wrong with this code?
Please help!
These are the relevant files:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
validates :fullname,presence: true
validates :description, presence: false
validates :balance, presence: true, numericality:true
before_validation :load_defaults
def load_defaults
if self.new_record?
self.balance = 100
end
end
has_many :products
has_many :orders
end
class Order < ActiveRecord::Base
belongs_to :user
belongs_to :product
validates :price, presence: true
validates :product_id, presence: true
validates :user, presence: true
end
class Product < ActiveRecord::Base
belongs_to :user
has_many :orders
end
class OrdersController < ApplicationController
before_action :authenticate_user!
def create
#order = current_user.orders.create(order_params)
#user.balance = balance: (#user.balance += #order.price)
redirect_to user_orders_path
end
end
def user_orders
#orders = current_user.orders
end
private
def order_params
params.require(:order).permit(:price, :user_id)
end
end
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
#products = #user.products
end
end
class ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:show]
def index
#products = current_user.products
end
def show
end
def new
#product = current_user.products.build
end
def edit
end
def create
#product = current_user.products.build(product_params)
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: 'Product was successfully created.' }
format.json { render :show, status: :created, location: #product }
else
format.html { render :new }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #product.update(product_params)
format.html { redirect_to #product, notice: 'Product was successfully updated.' }
format.json { render :show, status: :ok, location: #product }
else
format.html { render :edit }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
def destroy
#product.destroy
respond_to do |format|
format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_product
#product = Product.find(params[:id])
end
def product_params
params.require(:product).permit(:name, :description, :price)
end
end
<p>
User name: <%= #user.fullname %>
</p>
<p>
Balance: <%= #user.balance %>
</p>
ActiveRecord::Schema.define(version: 20171031150052) do
create_table "orders", force: :cascade do |t|
t.integer "user_id"
t.integer "product_id"
t.integer "price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "transactiontype"
t.integer "buyer_id"
t.integer "seller_id"
end
add_index "orders", ["product_id"], name: "index_orders_on_product_id"
add_index "orders", ["user_id"], name: "index_orders_on_user_id"
create_table "products", force: :cascade do |t|
t.string "name"
t.text "description"
t.integer "price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
end
add_index "products", ["user_id"], name: "index_products_on_user_id"
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "fullname"
t.string "description"
t.integer "balance"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
Rails.application.routes.draw do
devise_for :users
get 'pages/index'
resources :products
resources :users
resources :products do
resources :orders, only: [:create]
end
resources :orders, only: [:show]
get '/user_orders' => 'orders#user_orders'
end

If you assign an attribute directly you just assign a value and need call save yourself:
#user.balance = #order.price
#user.save!
Or you can use update (there is no balance_update), then you call it with a hash:
#user.update!(balance: #user.balance + #order.price)

Try
#user.update(balance: #user.balance + #order.price)

Related

Using Rails how to find booked classes from a user in a given period of time

I have an app where I post school classes and users can book classes. Now I have added stripe payments, with a monthly subscription. I would like to know how to show users how many classes they have booked since their monthly payment started.
I have tried this:
<%= #mylessons_lessons.count %>
But this only gives me the total lessons (classes) someone has booked since the beginning of time.
How could I find the booked lessons from each user depending on the date their subscription started and that only takes into account those of the last monthly subscription.
This is my lessons controller:
class LessonsController < ApplicationController
before_action :set_lesson, only: [:show, :edit, :update, :destroy, :mylessons]
before_action :authenticate_user!
# GET /lessons
# GET /lessons.json
def index
#lessons = Lesson.order(created_at: :asc)
end
# GET /lessons/1
# GET /lessons/1.json
def show
end
# GET /lessons/new
def new
#lesson = current_user.lessons.build
redirect_to root_path, warning: "You are not authorized" unless #current_user.admin?
end
# GET /lessons/1/edit
def edit
redirect_to root_path, warning: "You are not authorized" unless #current_user.admin?
end
# POST /lessons
# POST /lessons.json
def create
#lesson = current_user.lessons.build(lesson_params)
respond_to do |format|
if #lesson.save
format.html { redirect_to #lesson, notice: 'lesson was successfully created.' }
format.json { render :show, status: :created, location: #lesson }
else
format.html { render :new }
format.json { render json: #lesson.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /lessons/1
# PATCH/PUT /lessons/1.json
def update
redirect_to root_path, warning: "You are not authorized" unless #current_user.admin?
respond_to do |format|
if #lesson.update(lesson_params)
format.html { redirect_to #lesson, notice: 'lesson was successfully updated.' }
format.json { render :show, status: :ok, location: #lesson }
else
format.html { render :edit }
format.json { render json: #lesson.errors, status: :unprocessable_entity }
end
end
end
# DELETE /lessons/1
# DELETE /lessons/1.json
def destroy
redirect_to root_path, warning: "You are not authorized" unless #current_user.admin?
#lesson.destroy
respond_to do |format|
format.html { redirect_to lessons_url, notice: 'lesson was successfully destroyed.' }
format.json { head :no_content }
end
end
# Add and remove lessons to mylessons
# for current_user
def mylessons
type = params[:type]
if type == "add"
current_user.mylessons_additions << #lesson
redirect_to root_path, notice: "#{#lesson.title} ha sido añadida a tus clases"
elsif type == "remove"
current_user.mylessons_additions.delete(#lesson)
redirect_to root_path, notice: "#{#lesson.title} ha sido eliminada de tus clases"
else
# Type missing, nothing happens
redirect_to lesson_path(#lesson), notice: "Parece que no ha sucedido nada, prueba otra vez!"
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_lesson
#lesson = Lesson.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def lesson_params
params.require(:lesson).permit(:title, :description, :teacher, :thumbnail, :user_id, :date, :datetime, :lessonlink, :giphyimage, :game, :externalmaterial, :lessonage )
end
end
and my mylessons controller:
class MylessonsController < ApplicationController
before_action :set_lesson, only: [:show, :edit, :update, :destroy, :mylessons, :lessons]
before_action :authenticate_user!
def index
#mylessons_lessons = current_user.mylessons_additions
#lessons = Lesson.order(created_at: :asc)
end
end
and the schema from my db payments:
create_table "pay_charges", force: :cascade do |t|
t.bigint "owner_id"
t.string "processor", null: false
t.string "processor_id", null: false
t.integer "amount", null: false
t.integer "amount_refunded"
t.string "card_type"
t.string "card_last4"
t.string "card_exp_month"
t.string "card_exp_year"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "owner_type"
t.index ["owner_id"], name: "index_pay_charges_on_owner_id"
end
create_table "pay_subscriptions", id: :serial, force: :cascade do |t|
t.integer "owner_id"
t.string "name", null: false
t.string "processor", null: false
t.string "processor_id", null: false
t.string "processor_plan", null: false
t.integer "quantity", default: 1, null: false
t.datetime "trial_ends_at"
t.datetime "ends_at"
t.datetime "created_at"
t.datetime "updated_at"
t.string "status"
t.string "owner_type"
end
create_table "plans", force: :cascade do |t|
t.string "name"
t.integer "amount", default: 0, null: false
t.string "interval"
t.jsonb "details", default: {}, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "trial_period_days", default: 0
end
Conceptually the steps are:
check when user (paied) subscribed
get all classes from the date of subscription
show classes or number of classes in your view
You could use a scope in the model you want to check for start date of subscription, something like
scope :classes_after_subscription, ->(date) { where("created_at >= ?", date) }
and call it in your controller or in a decorator to use it in a view
classes_after_subscription("pass_user_sub_date_HERE").size

Why I can't create article with any category?

I'm new in RoR, and I'm working on Blog app, and implementing categories for articles. But I have trouble - when I create any article with some categories ('sport' or 'movie' or any other) I receive validation errors
- Category must exist
- Category can't be blank
But I have working dropdown list or categories (this helper):
def categories
category =
["Sport",
"Movie",
"Art",
"Nature",
"Exotic"]
category.each do |categ|
my_category = "#{categ}"
end
return category
end
And here is a piece of code of my article.new.html.erb file:
<p>
<%= f.label :category %><br>
<%= f.select :category, categories,
prompt: "Choose your category" %>
</p>
Also here is my db schema where categories fields are present:
create_table "articles", force: :cascade do |t|
t.string "title"
t.text "text"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "pic"
t.string "photo_file_name"
t.string "photo_content_type"
t.bigint "photo_file_size"
t.datetime "photo_updated_at"
t.string "music_file_name"
t.string "music_content_type"
t.bigint "music_file_size"
t.datetime "music_updated_at"
t.string "movie_file_name"
t.string "movie_content_type"
t.bigint "movie_file_size"
t.datetime "movie_updated_at"
t.string "category_id"
end
create_table "categories", force: :cascade do |t|
t.string "name"
t.text "desc"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "comments", force: :cascade do |t|
t.string "commenter"
t.text "body"
t.bigint "article_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["article_id"], name: "index_comments_on_article_id"
end
create_table "subscribers", force: :cascade do |t|
t.string "f_name"
t.string "l_name"
t.string "email"
t.string "country"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.string "userid"
t.string "email"
t.string "password_digest"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "admin", default: false
end
add_foreign_key "comments", "articles"
end
And here is my models:
class Article < ApplicationRecord
belongs_to :category
has_many :comments, dependent: :destroy
validates :title, presence: true, length: {minimum: 3}
validates :text, presence: true, length: {minimum: 3}
validates :category_id, presence: true
end
class Category < ApplicationRecord
has_many :articles
end
Also this is my Article controller:
class ArticlesController < ApplicationController
before_action :admin_authorize, :except => [:index, :show, :search]
def index
#articles = Article.includes(:category).order("created_at DESC")
if params[:category].blank?
#articles = Article.all.order("created_at DESC")
else
#category_id = Category.find_by(name: params[:category]).id
#articles = Article.where(category_id: #category_id).order("created_at DESC")
end
end
def new
#article = Article.new
#categories = Category.all.map{|c| [c.name, c.id]}
end
def show
#article = Article.find(params[:id])
end
def create
#article = Article.new(article_params)
#article.category_id = params[:category_id]
respond_to do |format|
if #article.save
format.html { redirect_to #article, notice: "Article was successfully created!" }
format.json { render :show, status: :created, location: #article }
else
format.html { render :new}
format.json {render json: #article.errors, status: :unprocessable_entity}
end
end
end
def edit
#article = Article.find(params[:id])
#categories = Category.all.map{|c| [ c.name, c.id ] }
end
def search
if params[:search].blank?
#articles = Article.all
else
#articles = Article.search(params)
end
end
def update
#article = Article.find(params[:id])
#article.category_id = params[:category_id]
if #article.update(article_params)
redirect_to #article
else
render 'edit'
end
end
def destroy
#article = Article.find(params[:id])
#article.destroy
redirect_to articles_path
end
private
def article_params
params.require(:article).permit(:title, :text, :search, :music, :movie, :photo)
end
def find_article
#article = Article.find(params[:id])
end
end
Thanks in advance!!
You forgot the category_id in your permitted params:
def article_params
params.require(:article).permit(:title, :text, :search, :music, :movie, :photo, :category_id)
end
You also need to change your select helper to send category_id and not category in the POST request.
Now, with your categories helper, you don't send any category id in your select dropdown, just some "category" names which are not bound to any Category instances.
You can fix the select like this and remove your helper:
<p>
<%= f.label :category %><br>
<%= f.select :category_id, Category.all.collect{|c| [c.name, c.id]},
prompt: "Choose your category" %>
</p>

Undefined Method for Active Record

When creating a new job, I get an error about an undefined method Employee. I will post relevant sections of my code; thanks in advance for the help!
Here is the error message:
undefined method `employee' for #
ActiveRecord::Associations::CollectionProxy []
_form.html.erb (where error is occuring):
<td colspan="4">Client-Job
# <%= text_field_tag 'client_num', #job.opportunities.employee.office.client_num, :size => "4", :readonly => true, :tabindex => -1 %>
-<%= f.text_field :number %></td>
Jobs Controller:
class JobsController < ApplicationController
before_action :set_job, only: [:show, :edit, :update, :destroy]
skip_load_and_authorize_resource
# GET /jobs
# GET /jobs.json
def index
#jobs = Job.all
end
# GET /jobs/1
# GET /jobs/1.json
def show
end
# GET /jobs/new
def new
#job = Job.new
end
# GET /jobs/1/edit
def edit
end
# POST /jobs
# POST /jobs.json
def create
#job = Job.new(job_params)
respond_to do |format|
if #job.save
format.html { redirect_to #job, notice: 'Job was successfully created.' }
format.json { render :show, status: :created, location: #job }
else
format.html { render :new }
format.json { render json: #job.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /jobs/1
# PATCH/PUT /jobs/1.json
def update
respond_to do |format|
if #job.update(job_params)
format.html { redirect_to #job, notice: 'Job was successfully updated.' }
format.json { render :show, status: :ok, location: #job }
else
format.html { render :edit }
format.json { render json: #job.errors, status: :unprocessable_entity }
end
end
end
# DELETE /jobs/1
# DELETE /jobs/1.json
def destroy
#job.destroy
respond_to do |format|
format.html { redirect_to jobs_url, notice: 'Job was successfully deleted.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_job
#job = Job.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def job_params
params.require(:job).permit(:opportunity_id, :number, :name, :flight_date, :flight_sub, :camera, :roll, :map_type, :plan_only, :lab_only, :est_hrs_model, :due_date, :edge_job_id, :custom_trans, :comp_inhouse, :delivered_date, :done, :control_in, :control_status, :at_date, :control_results, :control_check, :scan_staff, :scan_date, :scan_check, :comp_staff, :comp_date, :comp_check, :comp_sub, :comp_sub_due_date, :comp_sub_rec, :img_staff, :img_date, :img_check, :edit_staff, :edit_date, :edit_check, :notes, :file1, :file2, :file3, :file4, :file5, :add_files)
end
end
Employee Controller:
class EmployeesController < ApplicationController
before_action :set_employee, only: :show
skip_load_and_authorize_resource
# GET /employees
# GET /employees.json
def index
#employees = Employee.all
end
# GET /employees/1
# GET /employees/1.json
def show
end
# GET /employees/new
def new
#employee = Employee.new
end
# GET /employees/1/edit
def edit
end
# POST /employees
# POST /employees.json
def create
#employee = Employee.new(employee_params)
respond_to do |format|
if #employee.save
format.html { redirect_to #employee, notice: 'Contact was successfully created.' }
format.json { render :show, status: :created, location: #employee }
else
format.html { render :new }
format.json { render json: #employee.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /employees/1
# PATCH/PUT /employees/1.json
def update
respond_to do |format|
if #employee.update(employee_params)
format.html { redirect_to #employee, notice: 'Contact was successfully updated.' }
format.json { render :show, status: :ok, location: #employee }
else
format.html { render :edit }
format.json { render json: #employee.errors, status: :unprocessable_entity }
end
end
end
# DELETE /employees/1
# DELETE /employees/1.json
def destroy
#employee.destroy
respond_to do |format|
format.html { redirect_to employees_url, notice: 'Contact was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_employee
#employee = Employee.find(params[:id])
#opportunities = #employee.opportunities.all
end
# Never trust parameters from the scary internet, only allow the white list through.
def employee_params
params.require(:employee).permit(:office_id, :f_name, :l_name, :suffix, :position, :email, :phone, :ext, :mobile, :per_email, :per_phone, :archived, :replacement)
end
end
Job Model:
class Job < ActiveRecord::Base
mount_uploader :file1, AttachmentUploader
belongs_to :cost_proposal
has_many :opportunities
end
Employee Model:
class Employee < ActiveRecord::Base
belongs_to :office
has_many :opportunities
has_one :user
delegate :company, to: :office
validates :f_name, :l_name, presence: true
def self.emp_id(emp_id)
find_by(id: emp_id)
end
def self.emp_f_name(emp_id)
find_by(id: emp_id).f_name
end
def name_1
[f_name, l_name].compact.join(' ')
end
def full_name
if suffix?
[name_1, suffix].compact.join(', ')
else
name_1
end
end
def self.emp_full_name(emp_id)
find_by(id: emp_id).full_name
end
def full_phone
if ext?
[phone, ext].compact.join(' ext: ')
else
phone
end
end
end
Schema.rb:(relevant tables)
create_table 'employees', force: true do |t|
t.integer 'office_id'
t.string 'f_name'
t.string 'l_name'
t.string 'suffix'
t.string 'email'
t.string 'phone'
t.string 'ext'
t.string 'mobile'
t.string 'per_email'
t.string 'per_phone'
t.integer 'archived'
t.integer 'replacement'
t.datetime 'created_at'
t.datetime 'updated_at'
t.string 'position'
end
create_table 'jobs', force: true do |t|
t.integer 'cost_proposal_id'
t.string 'number'
t.string 'name'
t.date 'flight_date'
t.string 'flight_sub'
t.string 'camera'
t.string 'roll'
t.string 'map_type'
t.integer 'plan_only'
t.integer 'lab_only'
t.integer 'est_hrs_model'
t.date 'due_date'
t.integer 'edge_job_id'
t.integer 'custom_trans'
t.integer 'comp_inhouse'
t.date 'delivered_date'
t.integer 'done'
t.date 'control_in'
t.string 'control_status'
t.date 'at_date'
t.string 'control_results'
t.integer 'control_check'
t.string 'scan_staff'
t.date 'scan_date'
t.integer 'scan_check'
t.string 'comp_staff'
t.date 'comp_date'
t.integer 'comp_check'
t.string 'comp_sub'
t.date 'comp_sub_due_date'
t.integer 'comp_sub_rec'
t.string 'img_staff'
t.date 'img_date'
t.integer 'img_check'
t.string 'edit_staff'
t.date 'edit_date'
t.integer 'edit_check'
t.text 'notes'
t.string 'file1'
t.string 'file2'
t.string 'file3'
t.string 'file4'
t.string 'file5'
t.string 'add_files'
t.datetime 'created_at'
t.datetime 'updated_at'
t.integer 'flown'
t.integer 'cust_trans'
t.integer 'delivered'
t.string 'at_staff'
t.integer 'at_check'
t.integer 'opportunity_id'
end
**Update:**Adding opportunity client model/schema
Opportunity Model:
class Opportunity < ActiveRecord::Base
belongs_to :employee
has_one :user
has_many :film_specs
has_many :digital_specs
has_many :film_quotes
has_many :cost_proposals
has_many :jobs
validates :opp_status_id, presence: true
end
Opportunity Schema:
create_table 'opportunities', force: true do |t|
t.integer 'employee_id'
t.integer 'emp2_id'
t.integer 'emp3_id'
t.string 'name'
t.datetime 'prop_date'
t.integer 'opp_status_id'
t.string 'delay'
t.date 'con_signed'
t.integer 'quote_won_id'
t.float 'total_cost'
t.date 'exp_close'
t.integer 'pri_comp_id'
t.text 'notes'
t.datetime 'created_at'
t.datetime 'updated_at'
t.string 'lost'
t.string 'won'
t.string 'location'
t.integer 'pm_id'
t.integer 'job_id'
end
Client Model:
class Company < ActiveRecord::Base
mount_uploader :logo, LogoUploader
has_many :offices
has_many :employees, through: :offices
has_one :office_type
validates :name, uniqueness: { message: 'That company already exists' }
def self.master_company
find_by(type_id: 1)
end
def self.company_name(comp_id)
find_by(id: comp_id).name
end
end
Client schema:
create_table 'companies', force: true do |t|
t.string 'name'
t.string 'website'
t.string 'logo'
t.datetime 'created_at'
t.datetime 'updated_at'
t.integer 'type_id'
end
Your issue is that you're calling .employee on an ActiveRecord collection (#job.opportunities). It looks like you're trying to display the client number using #job.opportunities.employee.office.client_num which will never work since you would first need to select a single opportunity record to get its employee. You should revisit how your Job and Office models are associated.

Heroku Error Deleting a Post in Production: Rails

I am trying to delete a post in my app. It's working fine in localhost but when i pushed to heroku it's not working. I get an error saying "Something went wrong , Please check the logs". Here is my code:
posts_controller.rb
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user! , except: [:index,:show,:search]
before_filter :check_user, only: [:edit,:update,:destroy]
# GET /posts
# GET /posts.json
def search
if params[:search].present?
#posts = Post.search(params[:search])
else
#posts = Post.all
end
end
def index
if params[:tag]
#posts = Post.tagged_with(params[:tag])
else
#posts = Post.all
end
end
# GET /posts/1
# GET /posts/1.json
def show
#reviews = Review.where(post_id: #post.id)
end
# GET /posts/new
def new
#post = Post.new
end
# GET /posts/1/edit
def edit
#post = Post.find(params[:id])
end
# POST /posts
# POST /posts.json
def create
#post = Post.new(post_params)
#post.user_id = current_user.id
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 root_url, 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 root_path, 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, :description,:image,:all_tags)
end
def check_user
if current_user.id != #post.user_id
redirect_to root_path , alert: "Sorry this Post belongs to someone else"
end
end
end
The Logs
view/posts/index.html.erb
<h3>Posts</h3>
<table class="table">
<thead>
<tr>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #posts.each do |post| %>
<tr>
<td><h4><%=link_to post.title , post%></h4></td>
<td><%=raw tag_links(post.all_tags)%></td>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
<td><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<%end%>
</tbody>
</table>
models/post.rb
class Post < ActiveRecord::Base
searchkick
has_many :reviews , dependent: :destroy
has_many :taggings, dependent: :destroy
has_many :tags, through: :taggings
#Paperclip Installation
has_attached_file :image, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/missing.png"
validates_attachment_content_type :image, :content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif"]
def all_tags=(names)
self.tags = names.split(",").map do |name|
Tag.where(name: name.strip).first_or_create!
end
end
def all_tags
self.tags.map(&:name).join(", ")
end
def self.tagged_with(name)
Tag.find_by_name!(name).posts
end
end
Schema
ActiveRecord::Schema.define(version: 20151026124712) do
create_table "posts", force: :cascade do |t|
t.string "title"
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.string "tags"
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
end
create_table "reviews", force: :cascade do |t|
t.text "comment"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.integer "post_id"
end
create_table "taggings", force: :cascade do |t|
t.integer "post_id"
t.integer "tag_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "taggings", ["post_id"], name: "index_taggings_on_post_id"
add_index "taggings", ["tag_id"], name: "index_taggings_on_tag_id"
create_table "tags", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
t.string "name"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
create_table "votes", force: :cascade do |t|
t.integer "votable_id"
t.string "votable_type"
t.integer "voter_id"
t.string "voter_type"
t.boolean "vote_flag"
t.string "vote_scope"
t.integer "vote_weight"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "votes", ["votable_id", "votable_type", "vote_scope"], name: "index_votes_on_votable_id_and_votable_type_and_vote_scope"
add_index "votes", ["voter_id", "voter_type", "vote_scope"], name: "index_votes_on_voter_id_and_voter_type_and_vote_scope"
end
As the error log says, there are foreign keys related to posts in taggings table, so it does not allow you to delete posts.
I guess a post has many taggings, and a tagging belongs to a tag? In this case, you need to delete all taggings belong to the post you want to delete. The easiest way is adding dependent: :destroy to your post model like
# models/post.rb
has_many :taggings, dependent: :destroy
You have some records in Taggings table which referenced to Post record.
So you have several options -
has_many :taggings, dependent: :destroy
Or you can change yours migration:
add_foreign_key :taggins, :posts, on_delete: :cascade (you can add this in database migration)
Described here

Connecting two models in many-to-many relationship

I have a problem.
I want to get all matches in my player#show where player was engaged. So I did a many-to-many relationship.
Match model:
class Match < ActiveRecord::Base
has_many :match_schedules
has_many :players, through: :match_schedules
end
Player model:
class Player < ActiveRecord::Base
has_many :match_schedules
has_many :matches, through: :match_schedules
has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100>" }, :default_url => "/images/:style/missing.png"
validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/
end
and my match_schedule model:
class MatchSchedule < ActiveRecord::Base
belongs_to :player
belongs_to :match
end
If i do something like this in rails console:
p = Player.find 1
m = p.matches.new
m.playerA = “leo”
m.playerB = “cris”
p.save
It works, i can display loop with name:
<% #player.matches.each do |match| %>
<%= match.playerA %>
<% end %>
Problem is that i don't really know how I can connect matches to player in my new form, in browser. Already i have something like this:
Players_helper:
module PlayersHelper
def player_hash(players)
hash = Hash.new
players.each do |player|
hash["#{player.first_name}" + " " + "#{player.last_name}"] = player.first_name + player.last_name
end
hash
end
end
and _form:
<div class="form-inputs">
<%= f.select :playerA, options_for_select(player_hash(#abc)) %>
<%= f.select :playerB, options_for_select(player_hash(#abc)) %>
<%= f.input :PlayerApoints %>
<%= f.input :PlayerBpoints %>
</div>
Matches controller for new and create method looks like:
def new
#match = Match.new
#abc = Player.all
end
def create
#match = Match.new(match_params)
respond_to do |format|
if #match.save
format.html { redirect_to #match, notice: 'Match was successfully created.' }
format.json { render :show, status: :created, location: #match }
else
format.html { render :new }
format.json { render json: #match.errors, status: :unprocessable_entity }
end
end
end
And my schema.rb:
ActiveRecord::Schema.define(version: 20150706185030) do
create_table "match_schedules", force: :cascade do |t|
t.integer "match_id"
t.integer "player_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "matches", force: :cascade do |t|
t.string "playerA"
t.string "playerB"
t.integer "PlayerApoints"
t.integer "PlayerBpoints"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "players", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "avatar_file_name"
t.string "avatar_content_type"
t.integer "avatar_file_size"
t.datetime "avatar_updated_at"
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
end
You left out your match_params hash, so I have to do some guessing but something along the lines of:
in your Match class:
class Match < ActiveRecord::Base
has_many :match_schedules
has_many :players, through: :match_schedules
accepts_nested_attributes_for :match_schedules
end
in your controller:
def new
#match = Match.new
#match.match_schedules.build
#abc = Player.all
end
def create
#match = Match.new(match_params)
respond_to do |format|
if #match.save
format.html { redirect_to #match, notice: 'Match was successfully created.' }
format.json { render :show, status: :created, location: #match }
else
format.html { render :new }
format.json { render json: #match.errors, status: :unprocessable_entity }
end
end
end
in your match_params whitelist you'll need to add:
..., :player_ids => [])
since it is an array you need to put it after the other params.
You will also have to modify your view code. Basically you want to return a match_shedules_attributes => {player_ids => [1,2]} this gives you the ability to tell the MatchSchedule table the ID of each player associated with that match_id. You can do this with a fields_for inside the form_for block. See this http://guides.rubyonrails.org/form_helpers.html
So in the create action in the Match controller it should also save two records in the MatchSchedule table, one with each player's id and the id of that match.

Resources