Related
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
I'm currently stuck on a problem that I do not know how to tackle. I am currently working on a marketplace and a user can successfully, browse items, add items to cart and successfully purchase them items that are in a cart. I'm trying to build an admin side for the sellers to show a list of items that have been purchased but I am struggling as I do not know how to implement.
I have had a few ideas but nothing I think of seems to work.
If anyone can solve this I would be entirely grateful!
database
create_table "carts", force: :cascade do |t|
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "line_items", force: :cascade do |t|
t.bigint "product_id", null: false
t.bigint "cart_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "quantity", default: 1
t.bigint "order_id"
t.index ["cart_id"], name: "index_line_items_on_cart_id"
t.index ["order_id"], name: "index_line_items_on_order_id"
t.index ["product_id"], name: "index_line_items_on_product_id"
end
create_table "orders", force: :cascade do |t|
t.string "name"
t.text "address"
t.string "email"
t.integer "pay_type"
t.boolean "complete", default: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "products", force: :cascade do |t|
t.string "title"
t.text "description"
t.decimal "price", precision: 8, scale: 2
t.bigint "user_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "category_id"
t.index ["user_id"], name: "index_products_on_user_id"
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.string "username"
t.string "name"
t.boolean "admin", default: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.string "uid"
t.string "provider"
t.string "access_code"
t.string "publishable_key"
t.string "stripe_id"
t.boolean "subscribed"
t.string "card_last4"
t.string "card_exp_month"
t.string "card_exp_year"
t.string "card_type"
t.text "perk_subscriptions", default: [], array: true
t.string "s_name"
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
cart_controller
class CartsController < ApplicationController
before_action :set_cart, only: [:show, :edit, :update, :destroy]
rescue_from ActiveRecord::RecordNotFound, with: :invalid_cart
def index
#carts = Cart.all
end
def show
end
def new
#cart = Cart.new
end
def edit
end
def create
#cart = Cart.new(cart_params)
respond_to do |format|
if #cart.save
format.html { redirect_to #cart, notice: 'Cart was successfully created.' }
format.json { render :show, status: :created, location: #cart }
else
format.html { render :new }
format.json { render json: #cart.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #cart.update(cart_params)
format.html { redirect_to #cart, notice: 'Cart was successfully updated.' }
format.json { render :show, status: :ok, location: #cart }
else
format.html { render :edit }
format.json { render json: #cart.errors, status: :unprocessable_entity }
end
end
end
def destroy
#cart.destroy if #cart.id == session[:cart_id]
session["cart_id"] = nil
respond_to do |format|
format.html { redirect_to store_index_url, notice: 'Cart was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_cart
#cart = Cart.find(params[:id])
end
def cart_params
params.fetch(:cart, {})
end
def invalid_cart
logger.error "Attempt to access invalid cart #{params[:id]}"
redirect_to store_index_url, notice: 'Invalid cart'
end
end
lineitem controller
class LineItemsController < ApplicationController
include CurrentCart
before_action :set_cart, only: [:create]
before_action :set_line_item, only: [:show, :edit, :update, :destroy]
def index
#line_items = LineItem.all
end
def show
end
def new
#line_item = LineItem.new
end
def edit
end
def create
product = Product.find(params[:product_id])
#line_item = #cart.add_product(product)
respond_to do |format|
if #line_item.save
format.html { redirect_to(request.env['HTTP_REFERER']) }
format.js {#current_item = #line_item}
format.json { render :show,
status: :created, location: #line_item }
else
format.html { render :new }
format.json { render json: #line_item.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #line_item.update(line_item_params)
format.html { redirect_to #line_item, notice: 'Line item was successfully updated.' }
format.json { render :show, status: :ok, location: #line_item }
else
format.html { render :edit }
format.json { render json: #line_item.errors, status: :unprocessable_entity }
end
end
end
def destroy
#line_item.destroy
respond_to do |format|
format.html { redirect_to line_items_url, notice: 'Line item was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_line_item
#line_item = LineItem.find(params[:id])
end
def line_item_params
params.require(:line_item).permit(:product_id)
end
end
order controller
class OrdersController < ApplicationController
include CurrentCart
before_action :set_cart, only: [:new, :create]
before_action :ensure_cart_isnt_empty, only: :new
before_action :set_order, only: [:show, :edit, :update, :destroy]
# GET /orders
# GET /orders.json
def index
#orders = Order.all
end
# GET /orders/1
# GET /orders/1.json
def show
end
# GET /orders/new
def new
#order = Order.new
end
# GET /orders/1/edit
def edit
end
# POST /orders
# POST /orders.json
def create
#order = Order.new(order_params)
#order.add_line_items_from_cart(#cart)
respond_to do |format|
if #order.save
Cart.destroy(session[:cart_id])
session[:cart_id] = nil
format.html { redirect_to store_index_url, notice: 'Thank you for your order' }
format.json { render :show, status: :created, location: #order }
else
format.html { render :new }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /orders/1
# PATCH/PUT /orders/1.json
def update
respond_to do |format|
if #order.update(order_params)
format.html { redirect_to #order, notice: 'Order was successfully updated.' }
format.json { render :show, status: :ok, location: #order }
else
format.html { render :edit }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
# DELETE /orders/1
# DELETE /orders/1.json
def destroy
#order.destroy
respond_to do |format|
format.html { redirect_to orders_url, notice: 'Order was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_order
#order = Order.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def order_params
params.require(:order).permit(:name, :address, :email, :pay_type)
end
def ensure_cart_isnt_empty
if #cart.line_items.empty?
redirect_to store_index_url, notice: 'Your cart is empty'
end
end
end
product controller
class ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
# GET /products
# GET /products.json
def index
#products = Product.all
end
# GET /products/1
# GET /products/1.json
def show
end
# GET /products/new
def new
#product = Product.new
#product.user = current_user
end
# GET /products/1/edit
def edit
end
# POST /products
# POST /products.json
def create
#product = Product.new(product_params)
#product.user_id = current_user.id
respond_to do |format|
if #product.save
if current_user.can_receive_payments?
UploadProductJob.perform_now(#product)
end
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
# PATCH/PUT /products/1
# PATCH/PUT /products/1.json
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
# DELETE /products/1
# DELETE /products/1.json
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
# Use callbacks to share common setup or constraints between actions.
def set_product
#product = Product.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def product_params
params.require(:product).permit(:title, :description, :price, :category_id)
end
end
cart model
class Cart < ApplicationRecord
has_many :line_items, dependent: :destroy
def add_product(product)
current_item = line_items.find_by(product_id: product.id)
if current_item
current_item.quantity += 1
else
current_item = line_items.build(product_id: product.id)
end
current_item
end
def total_price
line_items.to_a.sum{ |item| item.total_price }
end
end
line_item model
class LineItem < ApplicationRecord
belongs_to :order, optional: true
belongs_to :product
belongs_to :cart, optional: true
def total_price
product.price.to_i * quantity.to_i
end
end
order model
class Order < ApplicationRecord
has_many :line_items, dependent: :destroy
enum pay_type: {
"Check" => 0, "Credit card" => 1, "Purchase order" => 2
}
validates :name, :address, :email, presence: true
validates :pay_type, inclusion: pay_types.keys
def add_line_items_from_cart(cart)
cart.line_items.each do |item|
item.cart_id = nil
line_items << item
end
end
end
product model
class Product < ApplicationRecord
belongs_to :user
belongs_to :category
has_many :line_items
before_destroy :ensure_not_referenced_by_any_line_item
private
def ensure_not_referenced_by_any_line_item
unless line_items.empty?
errors.add(:base, 'Line Items present')
throw :abort
end
end
end
You can tackle it. :)
Assuming a User is a seller, who has many Product, of which you want to show Product that have many LineItem that are associated to a complete Order:
current_user.products.joins(line_items: [:order]).where(orders: { completed: true })
This will require that your associations are correct.
What this is effectively doing:
orders = Order.where(completed: true)
line_items = LineItems.where(order: orders)
products = current_user.products.where(id: line_items.pluck(:product_id)
But because you can do that in one call to your database (make sure your indexes are correct), you should.
Use this code:
LineItem.joins(:orders).where('orders.complete' => true)
It will show you only LineItem-s which belong to some Order with complete field set to true, which, I believe, marks the Order as complete.
Then just show this result whenever you want to show it.
A little background, I took over a project that someone else started and hasn't worked on for 8ish months. The project is a CRM application built using Rails 4. I'm having a little trouble picking up where they left off, and am looking for help from seasoned Rails developers. The error I am receiving is when I try to add a new job from a job tracker page. The error I am receiving is:
ActionView::Template::Error (undefined method `opportunity' for #<Job:0x62d0240>):
1: <% #job[:opportunity_id] = params[:opportunity_id] %>
2: <% title "New #{#job.opportunity.name} Job"%>
3:
4: <%
5: #job[:name] = #job.opportunity.name
app/views/jobs/new.html.erb:2:in `_app_views_jobs_new_html_erb___882142983_51776136'
and the error is occuring on line 2 of the above. I will post relevant code, let me know if I need to add anything else. Thanks in advance!
Jobs new view (where error is occuring)
<% #job[:opportunity_id] = params[:opportunity_id] %>
<% title "New #{#job.opportunity.name} Job"%>
<%
#job[:name] = #job.opportunity.name
#pm = #job.opportunity.pm_id
%>
<br><br>
<%= render 'form' %>
Opportunity Controller
class OpportunitiesController < ApplicationController
before_action :set_opportunity, only: [:show, :edit, :update, :destroy]
load_and_authorize_resource
# GET /opportunities
# GET /opportunities.json
def index
#opportunities = Opportunity.all
end
# GET /opportunities/1
# GET /opportunities/1.json
def show
end
# GET /opportunities/new
def new
#opportunity = Opportunity.new
end
# GET /opportunities/1/edit
def edit
end
# POST /opportunities
# POST /opportunities.json
def create
#opportunity = Opportunity.new(opportunity_params)
respond_to do |format|
if #opportunity.save
format.html { redirect_to #opportunity, notice: 'Opportunity was successfully created.' }
format.json { render :show, status: :created, location: #opportunity }
else
format.html { render :new }
format.json { render json: #opportunity.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /opportunities/1
# PATCH/PUT /opportunities/1.json
def update
respond_to do |format|
if #opportunity.update(opportunity_params)
format.html { redirect_to #opportunity, notice: 'Opportunity was successfully updated.' }
format.json { render :show, status: :ok, location: #opportunity }
else
format.html { render :edit }
format.json { render json: #opportunity.errors, status: :unprocessable_entity }
end
end
end
# DELETE /opportunities/1
# DELETE /opportunities/1.json
def destroy
#opportunity.destroy
respond_to do |format|
format.html { redirect_to opportunities_url, notice: 'Opportunity was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_opportunity
#opportunity = Opportunity.find(params[:id])
#film_specs = #opportunity.film_specs.all
#digital_specs = #opportunity.digital_specs.all
end
# Never trust parameters from the scary internet, only allow the white list through.
def opportunity_params
params.require(:opportunity).permit(:employee_id, :emp2_id, :emp3_id, :name, :prop_date, :opp_status_id, :delay, :won, :lost, :con_signed, :quote_won_id, :total_cost, :exp_close, :pri_comp_id, :notes, :location, :pm_id)
end
end
Job 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 do |j|
if params[:opportunity_id].present?
j.opportunity_id = params[:opportunity_id]
end
end
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
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_presence_of :opp_status_id
end
Job Model
class Job < ActiveRecord::Base
mount_uploader :file1, AttachmentUploader
belongs_to :cost_proposal
has_many :opportunities
end
Job Schema
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
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
You don't have an opportunity method because it's a has_many relation, so you have opportunities and is an array. But you have the opportunitity_id so you can find your opportunity object.
opportunity = Opportunity.find(params[:opportunity_id])
This is my first time creating a Join table and I am a bit stuck. I have two tables: Categories and Products. I originally had it set up where Products belong to on category and Categories had many products. I just created a join table and changed my associations to has_and_belongs_to_many.
I have a form where multiple categories can be selected for a product but the categories selected are not saving in the database anymore.
In my controller I have created an array for category_id in my product params and I am wondering if there is something in my database that needs to be updated as well? Should I change categroy_id in database?
Here are my tables:
create_table "categories_products", id: false, force: :cascade do |t|
t.integer "category_id", null: false
t.integer "product_id", null: false
end
create_table "categories", force: :cascade do |t|
t.string "name"
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "product_id"
t.integer "category_id"
end
create_table "products", force: :cascade do |t|
t.string "title"
t.text "description"
t.string "image_url"
t.integer "price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "image", default: "{}"
t.integer "category_id"
t.integer "product_id"
end
Here are my model associations:
class Product < ActiveRecord::Base
has_and_belongs_to_many :categories, :join_table => :categories_products
class Category < ActiveRecord::Base
has_and_belongs_to_many :products, :join_table => :categories_products
the categories selector in my new product form:
<div class="field">
<%= f.label :category_ids %><br>
<%= f.select :category_ids, Category.all.collect {|x| [x.name, x.id]}, {}, :multiple => true %>
</div>
Products controller:
class ProductsController < ApplicationController
before_filter :authenticate_admin!, :except => [:index, :show, :earings]
before_action :set_product, only: [:show, :edit, :update, :destroy]
# GET /products
# GET /products.json
def index
#products = Product.all
respond_to do |format|
format.html # index.html.erb
format.js # index.js.erb
format.json { render json: #products }
end
end
def show
end
def new
#products = Product.new
#categories = Category.order(:name)
end
# GET /products/1/edit
def edit
#categories = Category.order(:name)
end
# POST /products
# POST /products.json
def create
#products = Product.new(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
# PATCH/PUT /products/1
# PATCH/PUT /products/1.json
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
# DELETE /products/1
# DELETE /products/1.json
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
# Use callbacks to share common setup or constraints between actions.
def set_product
#product = Product.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def product_params
params.require(:product).permit(:title, :description, :image, :price, :category_ids => [])
end
def search_params
default_params = {}
default_params.merge({user_id_eq: current_user.id}) if signed_in?
# more logic here
params[:q].merge(default_params)
end
end
I'm doing a website similar to Pinterest, but when I try that the users save the pins according to their id I get this error.. I´m using Rails 4... ¿How I fix this error?
NoMethodError in PinsController#create
undefined method `user_id=' for nil:NilClass
controllers/pins_controllers.rb
# POST /pins.json
def create
#pin.user_id = current_user.id
#pin = Pin.new(pin_params)
respond_to do |format|
end
model/pin.rb
class Pin < ActiveRecord::Base
belongs_to :user
validates :photo, presence:true
validates :description, presence:true
end
config/routes.rb
Pinterest::Application.routes.draw do
resources :pins
devise_for :users
root 'pages#index'
end
app/controllers/pins_controller.rb
class PinsController < ApplicationController
before_action :set_pin, only: [:show, :edit, :update, :destroy]
before_filter :authenticate_user!, except: [:index, :show]
# GET /pins
# GET /pins.json
def index
#pins = Pin.all
end
# GET /pins/1
# GET /pins/1.json
def show
end
# GET /pins/new
def new
#pin = Pin.new
end
# GET /pins/1/edit
def edit
end
# POST /pins
# POST /pins.json
def create
#pin = Pin.new(pin_params)
#pin.user_id = current_user.id
respond_to do |format|
if #pin.save
format.html { redirect_to #pin, notice: 'Pin was successfully created.' }
format.json { render action: 'show', status: :created, location: #pin }
else
format.html { render action: 'new' }
format.json { render json: #pin.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /pins/1
# PATCH/PUT /pins/1.json
def update
respond_to do |format|
if #pin.update(pin_params)
format.html { redirect_to #pin, notice: 'Pin was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #pin.errors, status: :unprocessable_entity }
end
end
end
# DELETE /pins/1
# DELETE /pins/1.json
def destroy
#pin.destroy
respond_to do |format|
format.html { redirect_to pins_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_pin
#pin = Pin.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def pin_params
params.require(:pin).permit(:name, :photo, :description)
end
end
db/migrate/schema.rb
ActiveRecord::Schema.define(version: 20140308225255) do
create_table "pins", force: true do |t|
t.string "photo"
t.string "description"
t.datetime "created_at"
t.datetime "updated_at"
t.string "name"
end
create_table "users", force: true 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 "phone"
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
How I fix this error?
NoMethodError in PinsController#create undefined methoduser_id=' for nil:NilClass`
Your action should be changed to:
# POST /pins.json
def create
#pin = Pin.new(pin_params)
#pin.user_id = current_user.id
end
Because you didn't create instance of Pin and want to assign value to it.