Rails Custom Validator - ruby-on-rails

I have a custom rails validator below that checks whether a new booking is available within the existing bookings based on the start and end date. I'm struggling to figure how I can add a separate 'room' validation. Each booking is for a room, so I want to make sure that the date range is only for the specified room and not for ALL bookings, just the bookings for the individual room. Any thoughts?
validates :start_date, :end_date, :presence => true, availability: true
class AvailabilityValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
bookings = Booking.where(void:'f')
date_ranges = bookings.map { |b| b.start_date..b.end_date }
date_ranges.each do |range|
if range.include? value
record.errors.add(attribute, "not available")
end
end
end
end
EDIT:
Following up on the schema. Fairly simple, all bookings are made by parent associated users ("user_id"), and room is simply another integer attribute within the record (there are 10 rooms).
create_table "bookings", force: :cascade do |t|
t.datetime "start_date"
t.datetime "end_date"
t.boolean "void", default: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "user_id"
t.integer "room"
t.index ["user_id"], name: "index_bookings_on_user_id"
end

Related

accepts_nested_attributes - ActiveRecord::UnknownAttributeError

I have a very simple model that each event has many forexes. I am trying to create a nested form to create new event with a bunch of forexes in a go.
class Event < ActiveRecord::Base
has_many :forexes
accepts_nested_attributes_for :forexes
end
class Forex < ActiveRecord::Base
belongs_to :event
end
The schema is like this:
ActiveRecord::Schema.define(version: 20180505093823) do
create_table "events", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "base"
end
create_table "forexes", force: :cascade do |t|
t.string "code"
t.float "rate"
t.integer "event_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "forexes", ["event_id"], name: "index_forexes_on_event_id"
end
And then I tried to create new objects using the following code in rails console. It fails.
Event.new( name: "11", base: "HKD", forexes_attributes: [ {code: "RMB", rate:1}, {code: "CNY",rate:2}])
It throws me back with this error.
ActiveRecord::UnknownAttributeError: unknown attribute 'forexes_attributes' for Event.
I know this is quite a basic question. And I have tried many different ways after researching in different places. I couldn't debug it. Appreciate your help.
In your Event controller you need to include the forexes_attributes in event_params method as along with default one
def event_params
params.require(:event).permit(forexes_attributes: Forexes_attribute_names.map(&:to_sym).push(:_destroy))
end

find a record that match another one (from another table)

I have three tables user, event, expected_event
My event are scrapped (every day with a rake task) from another
website
A user can create expected_event
So What I want to do is:
When a new event is found I want it to be compared to the Users expected_event...
If an event matches to any users expected_event then the users receive an email with the matching event (event.department, event.location_name)
I want to compare event.department to expected_event.department
I don't know how to do this...
expected_event.rb
class ExpectedEvent < ApplicationRecord
belongs_to :user
validates :department, presence: true
end
user.rb
class User < ApplicationRecord
has_many :expected_events
end
In the event model I have some methode to retreive city_name, location_nameand department
class Event < ApplicationRecord
def department
self.city[/\(.*?\)/].gsub(/[()]/, "").to_i
end
def city_name
self.city[/^[^\(]+/].rstrip!
end
def location_name
self.city[/\|(.*)/].gsub("|", "").strip
end
end
schema.rb
ActiveRecord::Schema.define(version: 20171210203403) do
create_table "events", force: :cascade do |t|
t.datetime "date"
t.string "city"
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 "nickname"
####
end
create_table "expected_events", force: :cascade do |t|
t.integer "department"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_expected_events_on_user_id"
end
end
EDIT
Is it correct if I add something like this to my user model?
has_many :matching_events, through: :events, source: :expected_events
When a new event is created, why don't you just query for ExpectedEvent records with matching paramters. Something like
event = Event.create(event_params)
if ExpectedEvent.where(city: event.city, ...).any?
#send email to user about the event
end

How would I go about allowing users to create surveys

Iv'e gotten myself into a bit of a brain mess up these past two days. I'd like to be able to allow my users to create a campaign (same concept as surveys), it will allow them to request certain data they wish such as an email address. This will then allow the person completing the form to proceed and receive a download link after entering an email. The email entered should be stored for the person who created the campaign to view.
Iv'e taken the approach with nested forms, however I ran into the trouble of allowing emails to be entered and saved for the campaign creator to view.
Any help is appreciated, thanks.
campaign.rb model
class Campaign < ActiveRecord::Base
belongs_to :user
has_many :queries
accepts_nested_attributes_for :queries
end
query.rb model
class Query < ActiveRecord::Base
belongs_to :campaign
has_many :results
end
result.rb model
class Result < ActiveRecord::Base
attr_accessible :content, :email, :query_id
belongs_to :query
end
schema.rb
create_table "campaigns", force: :cascade do |t|
t.string "title"
t.text "description"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "campaigns", ["user_id"], name: "index_campaigns_on_user_id", using: :btree
create_table "queries", force: :cascade do |t|
t.integer "campaign_id"
t.text "content"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "queries", ["campaign_id"], name: "index_queries_on_campaign_id", using: :btree
create_table "results", force: :cascade do |t|
t.integer "query_id"
t.text "content"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "results", ["query_id"], name: "index_results_on_query_id", using: :btree
Part of campaign_controller.rb
private
# Use callbacks to share common setup or constraints between actions.
def set_campaign
#campaign = Campaign.find(params[:id])
end
def campaign_params
params.require(:campaign).permit(:title, :description, :queries_attributes)
end
def query_params
params.require(:query).permit(:content, :email, :campaign_id)
end

I wanna use model attribute in view Rails

I am trying to use attribute value in model but its not working..
I have three models:
models/resident.rb
class Resident < ActiveRecord::Base
belongs_to :hostel
has_one :user,dependent: :delete
end
models/user.rb
class User < ActiveRecord::Base
belongs_to:resident
end
models/hostel.rb
class Hostel < ActiveRecord::Base
has_many :residents
has_one :rate_card,dependent: :delete
end
Schema
Resident
create_table "residents", force: :cascade do |t|
t.string "room_number"
t.string "roll_number"
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "hostel_id"
end
User
create_table "users", force: :cascade do |t|
t.string "roll_number"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "resident_id"
end
Hostel
create_table "hostels", force: :cascade do |t|
t.string "hostel"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Now i want to use the hostel attribute value in users/show.html.erb
I am able to do this :
<%if #user.resident.roll_number=="101303110"%>
if the roll number is present then returning true..
but if is use :
<%if #user.resident.hostel=="J"%>
and if J is a hostel present in Hostel model then it is returning false.
But when we put<%#user.resident.hostel%> in show.html.erb then it is showing value J.
How should I use related models attributes in each other view?
Given your associations, #user.resident.hostel would load a hostel. But you want to compare the hostel string on the hostel. Therefore your comparison should be:
<% if #user.resident.hostel.hostel == 'J' %>
Explanation:
#user # returns your a user
#user.resident # follows `belongs_to :resident` and
# returns a resident
#user.resident.hostel # follows `belongs_to :hostel` on the resident and
# returns a hostel
#user.resident.hostel.hostel # returns the value store in the `hostel`
# column of that `hostel`
Btw. I would argue that chaining calls like that violates the Law of Demeter. But it is hard to suggest any alternative without having more insights into your app.

Rails - One-direction table association - accessing data issue

I have two models:
class Order < ActiveRecord::Base
belongs_to :user
has_one :order_type
end
class OrderType < ActiveRecord::Base
belongs_to :order
end
my schema.rb:
create_table "order_types", force: :cascade do |t|
t.string "ort_name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "orders", force: :cascade do |t|
t.string "ord_name"
t.date "ord_due_date"
t.integer "user_id"
t.integer "ordertype_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "orders", ["ordertype_id"], name: "index_orders_on_ordertype_id"
add_index "orders", ["user_id"], name: "index_orders_on_user_id"
There is only one-direction association between them. The Order model has a column "ordertype_id" that links to the appropriate order_type.
My question is, what is the best practice to access the ort_name value for each #order in a view.
Currently, I am using:
<p>
<strong>Ord type:</strong>
<% OrderType.where(id: #order.ordertype_id).each do |t| %>
<%= t.ort_name %>
<% end %>
</p>
This solution results in many code repetitions. How I should change that? Can somebody advise, as I am not so experienced yet?
I tried this code, but it did not work:
#orders.order_type
There are many problems which you should address. It's ok to be a beginner, just take yourself time to learn and improve.
Schema
First off, your schema is set up badly. If you want to limit the order type to certain values, you should do this with a validation.
class Order
TYPES = %w[foo bar three four five]
validates :order_type, inclusion: { in: TYPES }
end
This way, you can easily add values in the future, and remove the complexity of adding a new model and its relations.
Column Names
Secondly, you should revise your column names. ord_name and ord_due_date is bad, it leads to ugly calls like order.ord_name. You should drop the prefix ord, it's superfluous.
Both steps would lead to this schema.rb
create_table "orders", force: :cascade do |t|
t.string "name"
t.date "due_date"
t.integer "user_id"
t.string "order_type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Logic placement
My final advice is to never call queries from your view. Logic should always be in the controller / model & passed to the view via instance variables.
This is a big no no in rails:
<% OrderType.where(id: #order.ordertype_id).each do |t| %>
...
<% end %>
In the end, accessing the type is simply accomplished with:
#order.order_type
Update your Order model to this:
class Order < ActiveRecord::Base
belongs_to :user
has_one :order_type, foreign_key: 'ordertype_id`
end
then order_type should be easily accessible:
#order.order_type.ort_name

Resources