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
Related
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
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!)
Can't mass-assign protected attributes: password, password_confirmation
Both of those fields are not mapped in the database, they are just fields in the form that I want to use to enable some nice validations.
Here is my model class:
class User < ActiveRecord::Base
attr_accessible :email, :password_hash, :password_salt
attr_accessor :password, :password_confirmation
before_save :encrypt_password
validates_confirmation_of :password
validates :password, presence: true
validates :email, presence: true
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
end
I was under the impression that by placing password and password_confirmation in the attr_accessor method they would not be mass assigned, yet here I am with this little issue.
Any suggestions?
Here's my migration field so you can see what fields are actually in my database.
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :email
t.string :password_hash
t.string :password_salt
t.timestamps
end
end
end
What am I missing here?
attr_accessible specifies a white list of model attributes that can be set via mass-assignment.
attr_accessor creating an instance variable (#name) and a corresponding access method to read it. Also creates a method called name= to set the attribute.
class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation
attr_accessor :password
before_save :encrypt_password
validates_confirmation_of :password
validates_presence_of :password, :on => :create
validates :email, presence: true
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
end
You need to add :password_confirmation and :password in attr_accessible
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).
In my model an Organisation has_many :users, and a User has_and_belongs_to_many :roles and a Role has a name and has_and_belongs_to_many :users.
In my Organisation class I have a method get_admin that is supposed to get the User belonging to that Organisation who has the Role 'admin'. Like so:
def get_admin
return self.users.with_role('admin')
end
Alas this returns an ActiveRecord::Relation object, not a User.
I tried appending .first to the end of the line like so
def get_admin
return self.users.with_role('admin').first
end
But then all I get is an SQL error
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: role.name: SELECT "users".* FROM "users" WHERE ("users".organisation_id = 2) AND (role.name == 'admin') LIMIT 1
My schema is defined thusly:
create_table "roles", :force => true do |t|
t.string "name", :null => false
end
create_table "users", :force => true do |t|
t.string "username", :null => false
t.integer "organisation_id"
end
create_table "roles_users", :id => false, :force => true do |t|
t.integer "user_id"
t.integer "role_id"
end
create_table "organisations", :force => true do |t|
t.string "name", :null => false
t.string "website", :null => false
end
How would I rewrite the Organisation's get_admin method (as follows) to return an actual User?
def get_admin
return self.users.with_role('admin')
end
Cheers
Dave
Create a scope called admin in Users model
user.rb:
scope :admin, joins(:role).where('roles.name = ?', 'admin')
And the get_admin method should be
def get_admin
return self.users.admin.first
end