Subscribed Members can Unlock Un-released Books - ruby

I've created an App where a signed up Members can access our Library of Books. If the Book's release_date is greater than today's date. Members have the ability to purchase an Unreleased Book & Unlock It(Early Bird Special).
But if the Unreleased Book has not been purchased, I would like to display it as Coming Soon.
I am having trouble creating a method/view that will help me display our Regular Books, Unreleased Books, & Purchased Books to a current_user.
My Code is Below, any help will be greatly appreciated.
VIEWS
<% if current_user.member? %>
<% #books.each do |book| %>
<% if book.unreleased_book %>
###I am having trouble getting this conditional or loop to work
<% if current_user has purchased the book %>
LIST ALL PURCHASED BOOKS
<% end %>
<% if current_user has not purchased the book %>
LIST ALL UNRELEASED BOOKS
<% end %>
<% elsif book.release_date <= Date.today %>
LIST ALL AVAILABLE BOOKS
<% end %>
<% else %>
DISPLAY ALL BOOKS AS STATIC
<% end %>
MODELS
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :member
has_many :books, through: :orders
has_many :orders, :dependent => :destroy
end
class Order < ActiveRecord::Base
attr_accessible :book_id, :order_date, :user_id
belongs_to :user
belongs_to :book
end
class Book < ActiveRecord::Base
attr_accessible :description, :pages, :title, :available_in, :price, :release_date
has_many :orders
has_many :users, through: :orders
###Definition of unreleased books
def unreleased_book
Date.today < self.release_date
end
end
CONTROLLER
class BooksController < ApplicationController
def index
#books = Book.all
#orders = current_user.orders
respond_to do |format|
format.html
format.json { render :json => #issues }
end
end
end
SCHEMA
create_table "users", :force => true do |t|
t.string "name"
t.string "email"
t.boolean "member", :default => false ###Becomes Member on SignUp
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "orders", :force => true do |t| ###Created when Purchased a BOOK
t.integer "user_id"
t.integer "book_id"
t.date "order_date"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "books", :force => true do |t|
t.string "title"
t.string "pages"
t.text "description"
t.decimal "price", :precision => 8, :scale => 2
t.date "release_date" ###If Release_Date > Time.Now then Book is Unreleased
t.datetime "created_at", :null => false
t.datetime "updated_at",
end

I think your model relations are a bit off. Here is my suggestion:
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :member
has_many :orders # a user typically can have many orders
end
class Order < ActiveRecord::Base
attr_accessible :book_id, :order_date, :user_id
belongs_to :user #each order belongs to a single user
has_many :books # one order can have consist of many books
end
class Book < ActiveRecord::Base
attr_accessible :description, :pages, :title, :available_in, :price, :release_date
belongs_to :order
has_many :users, through: order # since a book belongs to an order and an order belongs to a user, a book has many users goes the logic
end
Move the logic in your view to a help. consider using the case expression. This helper will give you an outline.
module BooksHelper
ActionView::Helpers::UrlHelper #this will give access to Url helpers
def purchases(book)
case book
when book.unreleased_book
link_to path_to_new_action #configure this path depending on how you set up your routes.
when current_user has purchased the book
#LIST ALL PURCHASED BOOKS
when current_user has_not purchased the book
#LIST ALL UNRELEASED BOOKS
when book.release_date <= Date.today
#LIST ALL AVAILABLE BOOKS
else
#DISPLAY ALL BOOKS AS STATIC
end
end
then in your VIEWS, render the helper like this.
<% if current_user.member? %>
<% #books.each do |book| %>
<%= purchases(book) %>
<% end %>
This will keep your views clean.
books controller:
since you changed your models associations, you need to tweak your controllers.
First, load the order (a specific order) by id. Then, since order has_many :books, find all the books associated with that order.
def index
#order = Order.find(params[:order_id])
#books = #orders.books
end
or if you have defined the current_user.orders, then you can do #orders = current_user.orders. but the way you have it now, the first line is not doing anything

Related

Active Admin Tag Collection with joined table

I have a problem to display the correct values in the Active Admin Tag collection.
enter image description here
To build many to many relationships I created a joined table:
create_table "profession_allocations", force: :cascade do |t|
t.integer "master_id"
t.integer "slave_id"
t.index ["master_id"], name: "index_profession_allocations_on_master_id", using: :btree
t.index ["slave_id"], name: "index_profession_allocations_on_slave_id", using: :btree
end
and a model:
class ProfessionAllocation < ApplicationRecord
has_and_belongs_to_many :master, :class_name => 'Profession'
has_and_belongs_to_many :slave, :class_name => 'Profession'
end
to build relationships with my profession table:
create_table "professions", force: :cascade do |t|
t.string "kind", null: false
t.string "list", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "summary_de", default: "summary german", null: false
t.string "summary_en", default: "summary english", null: false
end
and the model:
class Profession < ApplicationRecord
validates_presence_of :kind, :list
validates :kind, presence: true, uniqueness: true
validates :list, presence: true
validates :summary_de, presence: true
validates :summary_en, presence: true
has_many :master_profession_allocations, :class_name => 'ProfessionAllocation', :foreign_key => 'master_id'
has_many :slave_profession_allocations, :class_name => 'ProfessionAllocation', :foreign_key => 'slave_id'
end
Inside Active Admin I use the gem activeadmin_addons to use tags, but I guess this does not madder for this issue.
if f.object&.persisted?
f.input :master_profession_allocations, as: :tags, collection: Profession.where.not(id: f.object.id).order('summary_en ASC'), display_name: :summary_en
else
f.input :master_profession_allocations, as: :tags, collection: Profession.all.order('summary_en ASC'), display_name: :summary_en
end
end
While creating the ProfessionAllocation works fine with the Tag collection, the edit view makes problems, because it displays the ProfessionAllocations and not the related Professions.
My question is, how can I display the related Profession in the Tag Collection?
Best
Alex
I solved it by create a subsection. This allows me also to store addtional data in the allocation:
f.inputs do
f.has_many :master_profession_allocations, heading: 'Slaves', allow_destroy: true, new_record: true do |pa|
if f.object&.persisted?
pa.input :level, as: :select, collection: ProfessionAllocation::LEVELS
pa.input :slave_id, as: :select, collection: Profession.joins('LEFT JOIN profession_allocations pa on professions.id = pa.master_id WHERE professions.id !=' + f.object.id.to_s).map { |pa| [pa.summary_en, pa.id] }
else
pa.input :level, as: :select, collection: ProfessionAllocation::LEVELS
pa.input :slave_id, as: :select, collection: Profession.joins('LEFT JOIN profession_allocations pa on professions.id = pa.master_id').map { |pa| [pa.summary_en, pa.id] }
end
end
end

Create table if not present in existing database using Rails 3

I have a doubt.Suppose i have already created model(i.e-User) in Rails 3 application.Now i will connect my app to other database(lets say SQL Server) instead of my DB(where i have created this model before).That Database where i am going to connect has no "User" table and my app has already User.rb file.Here i need when i will connect to my app to that DB,it will automatically execute the query and create table in that DB.Please check my User migration file given below.
20150419131135_create_users.rb:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :contact_name
t.string :login_id
t.string :password_hash
t.string :password_salt
t.string :phone
t.string :address
t.timestamps
end
end
end
User.rb:
class User < ActiveRecord::Base
attr_accessible :address, :contact_name, :login_id, :password_hash, :password_salt, :phone,:password, :password_confirmation
attr_accessor :password
before_save :encrypt_password
validates_confirmation_of :password
validates_presence_of :password, :on => :create
validates :contact_name, :presence => true, :length => { :minimum => 5 }
validates :login_id, :presence => true
validates_uniqueness_of :login_id
def encrypt_password
if password.present?
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
end
end
def self.authenticate(username, password)
user = find_by_login_id(username)
if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
user
else
nil
end
end
end
When user will connect to any other DB,The table should auto created.Please help me.
Change your migration file to check before creating/destroying users
class CreateUsers < ActiveRecord::Migration
def self.up
if !table_exists? :users
create_table :users do |t|
t.string :contact_name
t.string :login_id
t.string :password_hash
t.string :password_salt
t.string :phone
t.string :address
t.timestamps
end
end
end
def self.down
drop_table :users if !table_exists?(:users)
end
end

Unpermitted parameters - Rails 4.1.1, Ruby 2.1.2

I cannot seem to get to the bottom of where I am going wrong. My "order.rb" fields populate ok, but I can't get the "order_row" table values to populate. I just keep getting the following error in terminal(not worried about date for now, should be ok with that)...
Unpermitted parameters: date(i), order_row
Customer model(customer.rb)...
class Customer < ActiveRecord::Base
has_many :orders, dependent: :destroy
end
Order model(order.rb)...
class Order < ActiveRecord::Base
belongs_to :customer
has_many :order_rows, dependent: :destroy
accepts_nested_attributes_for :order_rows
end
Order_Row model(order_row.rb)
class OrderRow < ActiveRecord::Base
belongs_to :order
end
(orders_controller.rb)....
def new
#order = Order.new
end
def create
#order = Order.new(order_params)
respond_to do |format|
if #order.save
format.html { redirect_to(#order, :notice => 'Order was successfully created.') }
else
format.html { render :action => "new" }
end
end
end
private
def order_params
params.require(:order).permit(:customer_id, :date, :total,
:order_row_attributes => [:description, :quantity, :price, :order_id])
end
Form code on new.html.haml
= semantic_form_for #order do |f|
= f.input :customer_id, :as => :select, :collection => Hash[Customer.all.map{|c| [c.company,c.id]}]
= f.input :date
= f.fields_for :order_row do |ff|
= ff.input :description
= ff.input :quantity
= ff.input :price
= ff.hidden_field :order_id
= f.input :total
= f.action :submit, :as => :button
The problem is this line order_row_attributes.It should be order_rows_attributes. And with the date not being permitted,try changing the date attribute to some name like order_date.
This should work
private
def order_params
params.require(:order).permit(:customer_id, :order_date, :total,
:order_rows_attributes => [:description, :quantity, :price, :order_id])
end
I got it working by changing the new method to....
def new
#order = Order.new
#order.order_rows.build
end
So combination of this and Pavans answer did the trick.

Rails migrations: Drop table and change references

Help me please create a correct migration for next needs
Drop table "hiring_question_groups"
Change references (:group) in "hiring_questions" to references(:company)
I have this migration before:
class CreateHiringQuestionsAndGroups < ActiveRecord::Migration
def change
create_table :hiring_questions do |t|
t.references :group
t.string :title
t.text :description
t.boolean :is_active, default: true
t.timestamps
end
create_table :hiring_question_groups do |t|
t.references :company
t.string :title
t.boolean :is_active, default: true
t.timestamps
end
end
end
Table which should be dropped:
class Hiring::QuestionGroup < ActiveRecord::Base
belongs_to :company
has_many :questions, class_name: 'Hiring::Question', dependent: :destroy, foreign_key: 'group_id'
This table should be changed:
class Hiring::Question < ActiveRecord::Base
belongs_to :group, class_name: 'Hiring::QuestionGroup'
to:
class Hiring::Question < ActiveRecord::Base
belongs_to :company, class_name: ???
How I can do this with One migration?
That's very simple!
def change
remove_reference :hiring_questions, :group
drop_table :hiring_question_groups
add_reference :hiring_questions, :company
end
Sorry!)

rails-3.1 | Is this a case for a nested form or a case for something else?

I am working on an app to be used as a logbook for aircraft. I may be headed in the wrong direction with design of my db. Any recommendations on that would be useful. Is this a situation for nested forms? Or is that only if I need to actually create a record for both models at the same time?
As of now this is how I have laid out the models:
class Location < ActiveRecord::Base
has_many :aircrafts, :pilots
end
class Aircraft < ActiveRecord::Base
belongs_to :location
has_many :trips
end
class Pilot < ActiveRecord::Base
belongs_to :location
has_many :trips
end
class Trip < ActiveRecord::Base
belongs_to :aircraft, :pilot
end
ActiveRecord::Schema.define(:version => 20120209014016) do
create_table "aircrafts", :force => true do |t|
t.string "tail_number"
t.decimal "hobbs"
t.integer "location_id"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "aircrafts", ["location_id"], :name => "index_aircrafts_on_location_id"
create_table "locations", :force => true do |t|
t.string "city"
t.string "state"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "pilots", :force => true do |t|
t.string "first_name"
t.string "last_name"
t.string "email"
t.integer "location_id"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "pilots", ["location_id"], :name => "index_pilots_on_location_id"
create_table "trips", :force => true do |t|
t.date "date"
t.integer "aircraft_id"
t.decimal "hobbs_out"
t.decimal "hobbs_in"
t.integer "cycles_airframe"
t.integer "cycles_left"
t.integer "cycles_right"
t.time "time_out"
t.time "time_in"
t.integer "pic_id"
t.integer "sic_id"
t.string "flight_sequence"
t.text "remarks"
t.integer "miles"
t.datetime "created_at"
t.datetime "updated_at"
end
end
What I want to be able to do is to create a new trip record and update the :hobbs column in the Aircraft record. With the Aircraft table I essentially want to track the current hobbs time (or think of it as the current mileage on a car). When I create a new trip it will use the current hobbs time for the hobbs_out attribute and the hobbs_in will be recorded in the trip and be used to update the Aircraft.hobbs.
Can I do this with code in the trip_controller? Something like:
def create
#trip = Trip.new(params[:trip])
#aircraft = Aircraft.where(params[:trip][:aircraft_id])
#aircraft.hobbs = params[:trip][:hobbs_in]
#aircraft.save
respond_to do |format|
if #trip.save
format.html { redirect_to #trip, notice: 'Trip was successfully created.' }
format.json { render json: #trip, status: :created, location: #trip }
else
format.html { render action: "new" }
format.json { render json: #trip.errors, status: :unprocessable_entity }
end
end
end
If it is more of a nested form circumstance, how would I get the form to just update the Aircraft record and create a new Trip record?
Thanks!
Personally I would actually have Planes and Airports and structure the db as follows via these rails associations and then go from there:
class Airport < ActiveRecord::Base
has_many :planes
belongs_to :trip
end
class Plane < ActiveRecord::Base
belongs_to :Airport # Current location
has_many :trips
has_many :pilots, :through => :trips
end
class Pilot < ActiveRecord::Base
has_many :trips
has_many :planes, :through => :trips
end
class Trip < ActiveRecord::Base
belongs_to :plane
belongs_to :pilot
has_many :airports
end
I think the nesting you reference will be more relevant in designing your routes perhaps.
For instance if you are doing RESTful routes and you nest one :resource within another :resource than you get all the rails helpers to use that relationship. You just need to do a couple of things like have forms do form_for[OuterModelName, InnerModelName]. For the most part however Rails will handle the details.
For resources (think tables/models) that you do want to be able to access separately (think, you want to update a plane, independently of say an Airport) then you need to have resources :plane as a separate route line as(as well as having it nested), i.e. there will be two references to that resource.
As a final note, it's resources when you'll have an index view (multiple records) and resource when you are just using one instance (show, edit, update, etc).

Resources