how to implement an opening_time model in rails 3 - ruby-on-rails

I want to implement an opening time mode for a store.
currently i have
Class Store
has_one :opening_table
#return opening_times as an array
def opening_times
self.build_opening_table unless opening_table
(0..6).collect{ |i|
[opening_table.read_attribute("open_#{i}"),opening_table.read_attribute("close_#{i}") ]
}
end
def opening_times=(attr)
self.build_opening_table unless opening_table
i=0
attr.each do |el|
opening_table.attributes= {"open_#{i}".to_sym => el[0]}
opening_table.attributes= {"close_#{i}".to_sym => el[1]}
i=i+1
end
end
and OpeningTable has fields open_0, close_0 for monday opening and closing time
create_table :opening_tables do |t|
t.references :advertisement, :null=>false
(0..6).each do |i|
t.integer "open_#{i}"
t.integer "close_#{i}"
end
t.timestamps
end
i dont feel comfortable and flexible with this solution but i dont have an idea to implement it in a better way

You could make another table called Schedule
create_table :schedules do |t|
t.integer 'open'
t.integer 'close'
t.integer store_id
t.timestamps
end
And then make the store has _many :schedules
So you can acces Store.first.schedules[0].open And so on.
EDIT:
For the nested attribute, you would simply access through the store.schedules[0]
or you could add to the schedules table:
t.string :week_day
and then do store.schedules.find_by_week_day("monday")
As for the validation, add that to your models/store.rb
validate :has_seven_schedules
...
def has_seven_schedules
self.schedules.count == 7 ? true : false
end
EDIT2:
If you wanted you could put that find_by_week_day("monday") on a method inside the store.rb model like:
def opening_time(day)
schedule = self.schedules.find_by_week_day(day)
unless schedule.nil?
return schedule.open
end
end
And the same for the closing_time.

Related

Querying the database passing multiple parameters rails

I have a user table and an activity table. The user has many activities. This is what i have in my users table:
class SorceryCore < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :first_name
t.string :surname
t.integer :previous_award
t.integer :chosen_award
t.string :email, :null => false
t.string :crypted_password
t.string :salt
t.timestamps
end
add_index :users, :email, unique: true
end
This is what I have in my activities table:
class CreateActivities < ActiveRecord::Migration
def change
create_table :activities do |t|
t.integer :activity_type
t.string :activity_name
t.string :approver_email
t.references :users, index: true, foreign_key: true
t.timestamps null: false
end
end
In my view I want to show the activity_name, where user_id = the current user's id, and where the the activity_type = 1. I'm not sure where to write this method or how to call it either. I have read through the following link but can't seem to get anything working. http://guides.rubyonrails.org/active_record_querying.html
I think I need to use something along the lines of this:
Activity.where("activity_type <= ?", 1).where("user_id <= ?", current_user.id)
But I'm not sure if this is supposed to go into a method in the controller or the model, and I'm not sure which controller or model it's supposed to go into
In the User model:
# user.rb
def activity_by_type(type = 1)
self.activities.where(activity_type: type).first
end
and then, you can call current_user.activity_by_type(<specify the type here>)
You can use the above method to get any of the activity type for the specified user, by specifying the type in the method call.
One advice I'll give though is to try and use the concept of enums to categorize your activity_type column in the activities table. An example on how, can be found here.
You simply have to query on the current_user.activities association:
#activities = current_user.activites.where(activity_type: "1")
You could also use a scope (which is what SunnyK recommended):
#app/models/user.rb
class User < ActiveRecord::Base
has_many :activities
scope :by_type, ->(type = 1) { activities.where(activity_type: type) }
end
--
If you only wanted to return a single record, you'd have to replace .where with .find_by:
#activity = current_user.activities.find_by activity_type: 1
--
Since you're using an enum, you may wish to use the built-in class method that you'd be able to call:
enum activity_type: [:sports, :photography]
#activity = current_user.activities.sports

Rails: RSPEC test for updating active record entry is failing

I have two models: Draft and Pick. I want the Draft's ActiveRecord column current_pick to increase by 1 after a Pick is created.
Inside Pick, I have a method that increase draft.current_pick by 1:
class Pick < ActiveRecord::Base
belongs_to :draft
after_save :advance_draft
def advance_draft
draft.updraft
end
Inside draft, updraft is:
def updraft
self.current_pick += 1
end
My test to ensure the current_pick is being increased by one is:
it 'should run the advance_draft method after creating' do
team1 = FactoryGirl.create(:team)
team2 = FactoryGirl.create(:team_two)
cam = FactoryGirl.create(:player)
draft = FactoryGirl.create(:two_team_draft)
pick = Pick.create(:player_id => cam.id, :team_id => draft.team_at(draft.current_pick).id, :draft_id => draft.id, :draft_position => draft.current_pick)
draft.draft_position.should eq 2
end
The pick and draft are being created in the test but the updraft method is not being called on the correct draft because the pick.draft.draft_position remains at 1 after the pick has been created. (it should increase to 2).
Here is my schema:
create_table "drafts", force: true do |t|
t.integer "draft_position"
t.integer "number_of_teams"
t.integer "PPTD"
t.integer "PPR"
t.integer "current_pick", default: 1
end
create_table "picks", force: true do |t|
t.integer "player_id"
t.integer "team_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "draft_id"
t.integer "draft_position"
end
My question is, how do I properly increase the pick.draft.current_pick inside my test?
I would do 2 things, use increment! when updating the count to increment the value and save the record, and reload the object you're looking at, since its database representation has changed since it was created.
def updraft
increment!(:current_pick)
end
This will update the current_pick and save the object in one shot.
it 'should run the advance_draft method after creating' do
# ... setup
draft.reload.draft_position.should eq 2
end
Now, instead of using the instance of draft that was created before the modification occurred, it's using a version current with the database.

is their any date filter in ruby?

1)
i have a leave request form in my HRM application, i want that when a user enter the "from_date", the "to_date" should be greater than "from_that"?
2)
In my app i have a leave model in which user can defined leave type and day's allowed.In my second model leave_request user can request for leave according to leave type.Everything is working well.Now i want to display leave balance available to user on basis of allowed day's in leave_request form?
Migration leave.rb:
class CreateLeaves < ActiveRecord::Migration
def self.up
create_table :leaves do |t|
t.integer :user_id
t.integer :company_id
t.string :leave_type
t.integer :allowed_leaves
t.text :description, :limit => 500
t.timestamps
end
end
def self.down
drop_table :leaves
end
end
And leave_request.rb:
class CreateLeaveRequests < ActiveRecord::Migration
def self.up
create_table :leave_requests do |t|
t.integer :employee_id
t.integer :leave_type
t.date :from_date
t.date :to_date
t.text :reason_for_leave
t.string :contact_during_leave, :limit => 10
t.integer :user_id
t.integer :company_id
t.timestamps
end
end
def self.down
drop_table :leave_requests
end
end
And can i validate number of leaves available like if user do not have enough leave balance than their should be a message like"You do not have enough leave to request " etc.
Your first question is not very comprehensible. What is "from_that"? If you're asking how to check if one date is before or after another, it's easy: Date and DateTime include Comparable so you can compare any two just like you would two numbers, e.g.:
>> DateTime.now > 1.day.ago
# => true
>> DateTime.now > Date.tomorrow
# => false
You can write your own validator, something like this (untested code):
class LeaveRequest < ActiveRecord::Base
validate :has_enough_leave
def has_enough_leave
if( to_date - from_date > employee.allowed_leave.days )
errors.add(:to_date, "You do not have enough leave to requestt")
end
end
...
I have done my first problem in following way:
class LeaveRequest < ActiveRecord::Base
belongs_to :user
belongs_to :leave
validate :from_date_and_to_date
def from_date_and_to_date
if(to_date != from_date)
errors.add(:to_date, " should be greater than from date" )
end
end
Hi friends here i came with a new answer of my second question
i used following line of code to fix my problem:
<label>Leave Type</label>
<label>Balance</label>
<% for leave in #leave_types %>
<%= leave.leave_type %>
<%= leave.allowed_leaves%>
<% end %>
This displayed all my leave_types in my new leave_request form.

how to write this query of many-to-many base in rails

Hey guys
I'm new to rails, There's a lot of eye-opener for me, and I write some code and it seems no efficient, I paste my code below, could you help me find a better way to write this.
videos table:
class CreateVideos < ActiveRecord::Migration
def self.up
create_table :videos do |t|
t.string :title
t.string :desc
t.string :tudou
t.string :otherurl
t.timestamps
end
end
def self.down
drop_table :videos
end
end
drummers table:
class CreateDrummers < ActiveRecord::Migration
def self.up
create_table :drummers do |t|
t.string :first_name
t.string :middle_name
t.string :last_name
t.string :nick_name
t.boolean :gender
t.timestamps
end
end
def self.down
drop_table :drummers
end
end
and I set them to simple many-to-many association
class CreateDrummersVideosJoin < ActiveRecord::Migration
def self.up
create_table :drummers_videos, :id => false do |t|
t.integer "drummer_id"
t.integer "video_id"
end
end
def self.down
drop_table :drummers_videos
end
end
I want to find all the title of drummer first name is "Jojo" last name is "Mayer"'s video
my code:
title = Drummer.where(:first_name => "Jojo", :last_name => "Mayer").first.videos.each {|t| t.title}
This return all the column's data, not the only the title I want
and since the there's only one result return named "Jojo Mayer", But the return value is activeRelation, I can't call videos, so my work around is using :first to get the video instance in order to call the videos. I know it's definitely not the way doing it
any suggestion?
You need a join table in between them like you infer. But that join table in Rails does not have to be created in a migration. It can be done exclusively in the models.
#drummer.rb
belongs_to :drummer_videos, :polymorphic => true
has_many :videos, :as => :drummer_videos
#video.rb
belongs_to :drummer_videos, :polymorphic => true
has_many :drummers, :as => :drummer_videos
Make sure that the drummer TABLE and video TABLE have a drummer_videos_id attribute.
Then you can call your Drummer..
Drummer.where(:first_name => "Jojo", :last_name => "Mayer").videos.each {|t| t.title}
First off, if you want to get only the title attribute from the videos you should use map or collect instead of each, so something like this:
Drummer.where(...).first.videos.map{ |t| t.title }
or even shorter:
.map(&:title)
Second, it seems to me that if you really want to get all the videos from a single Drummer object, than using first in some way or another, like you do, is a pretty good option.
Otherwise, if you want to get all videos from different Drummers according to a certain criteria, then you should probably call Video directly and then join or include the Drummer. Perhaps like this:
Video.joins(:drummers).where("drummers.first_name = 'jojo' AND drummers.last_name = 'Mayer'").map(&:title)

id field without autoincrement option in migration

I have a DB migration like so:
class CreateParticipations < ActiveRecord::Migration
def self.up
create_table(:participations, :primary_key => 'Seat') do |t|
t.integer :Seat
t.string :Nickname
t.string :Clan
t.string :FirstName
t.string :LastName
t.string :Email
t.boolean :Payed
t.timestamps
end
end
def self.down
drop_table :participations
end
end
Now, seat is created with an Auto increment. However, I do not want that. I want it without an auto increment. I will define Seat myself in my Logic.
I have been looking around but I cannot find how to disable auto_increment.
How do I do this? Except for manually doing it in MySQL.
For the record, if you absolutely need to do this (it shouldn't happen often), here's the way to do a non-autoincrementing primary key with the Rails migration DSL:
create_table(:table_name, :id => false) do |t|
t.integer :id, :options => 'PRIMARY KEY'
end
That will work for MySQL anyway, if your DB uses different syntax to specify a primary key, replace the :options => 'PRIMARY KEY' with whatever that is.
This question is 3 years old, but incase anyone is wondering 3 years later, like I was, all you do is "change_column" in the event the table is already created:
change_column(:table_name, :id, :integer, :null => false)
This should work in Rails 2.x and 3.x.
O
Not saying its a good idea, but here's how I did it for SQLite3 - just replace that SQLiteAdapter with your DB's adapter - you might do this cleaner/short with a call to define_method
class AbstractAdapter
end
module ActiveRecord
module ConnectionAdapters
class SQLiteAdapter < AbstractAdapter
def supports_autoincrement?
false
end
end
end
end
<then you migration>
or
class SomeMigration < ActiveRecord::Migration
def change
create_table :table do |t|
ActiveRecord::ConnectionAdapters::SQLiteAdapter.send :define_method, :supports_autoincrement? do false end
t.integer etc
end
end
end
Of course just change the adapter for other db's
Is there a reason you can't use rails' id key and manually add an index called Seat?
I've seen some hacks just to get rails to -work- on non-increment-pk databases. I don't think it's an option. If I recall, that's how rails accesses all its per-row functionality.
Honestly, how -absolutely- do you need that slight boost in efficiency of ignoring rails' structure?
I think the real answer is "you can't." Activerecord has a few things it will not bend on.

Resources