Hi I have two models which are related to each other through a third model. The two main models are User and Club which have a relation through the Reservations table. The Reservation model has a column called active which is a boolean. The relationship between User and Club is a has_many to has_many ,through Reservation
When a user makes a reservation in a club, an entry is made in the reservation table and the field in the reservation active column is set to true. If the user makes another reservation at the same club, then the previous reservation should have the active column updated from true to false
Here is my code:
user = User.where(:email => params["user_email"]).first
club = Club.find(params["club_id"].to_i)
reservation = Reservation.new
reservation.club_id = club.id
reservation.user_id = user.id
reservation.active = true
user.reservations.where("club_id = ? AND active = ?", club.id, true).each do |res|
puts res.id
res.active = false
res.save
end
reservation.save
Now the user.reservations.where("club_id = ? AND active = ?", club.id, true) query returns the correct entries. I update the value and save it again. However when I look in the database I still see active column has the value true.
What is even stranger is when I run the same command, which I used in my code, in the rails console, it returns the correct entries. When I modify the command a bit and try to find all the entries with column marked as false I also get the right entries. If I select an entry which should have active marked as false, and try this reservation.active == false this returns false, but when I run user.reservations.where("club_id = ? AND active = ?", club.id, true) the results does not contain the entry.
Can anyone explain why I am seeing such strange behaviour. Thanks in advance
* UPDATE *
Here is my schema
create_table "reservations", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "club_id"
t.integer "user_id"
t.boolean "active"
end
create_table "clubs", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "name"
end
create_table "users", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "email"
end
Related
I have two models
name
user model
result model
user model contains email, password, sign_in_time etc
result model contains user_email and result fields
I want to fetch email from user model into result model's user_email fields
how can I achieve this
That's the schema files of both
create_table "users", force: :cascade do |t|
t.string "email", limit: 255, default: "", null: false
t.string "encrypted_password", limit: 255, default: "", null: false
t.string "reset_password_token", limit: 255
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", limit: 4, default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip", limit: 255
t.string "last_sign_in_ip", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "admin", limit: 1
t.boolean "superadmin", limit: 1, default: false, null: false
end
result
create_table "results", force: :cascade do |t|
t.string "user_email", limit: 255
t.integer "result", limit: 4
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
please help me!
Have you set relationship between user model and result model? Can you explain more detail? Basically, If you want to get data from another model to a model, I think you have to set relationship for 2 models.
The Key model has the following migration
class CreateKeys < ActiveRecord::Migration
def change
create_table :keys do |t|
t.string :value
t.integer :alive_time
t.integer :block_time
t.timestamps null: false
end
end
end
Running the following does not update the block_time value:
#available_keys = Key.where(:block_time => 0)
#key = Key.find(#available_keys[0].id)
#key.update_attribute(:block_time, Time.now.to_i)
I tried some variants in the rails console:
Running: Key.find(10).update_attributes({:block_time => Time.now.to_i})
Causes: UPDATE "keys" SET "value" = ?, "alive_time" = ?, "updated_at" = ? WHERE "keys"."id" = ?
The SQL being run updates the alive_time but not the block_time
Why? How do I ensure correct behaviour?
EDIT
The schema.rb contents:
ActiveRecord::Schema.define(version: 20150708123716) do
create_table "keys", force: :cascade do |t|
t.string "value"
t.integer "alive_time"
t.integer "block_time"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
I created three models:
class Role < ActiveRecord::Base
has_many :users
has_and_belongs_to_many :permissions
accepts_nested_attributes_for :users, :permissions
end
class Permission < ActiveRecord::Base
has_and_belongs_to_many :roles
accepts_nested_attributes_for :roles
end
and a migration as following:
class Changetable < ActiveRecord::Migration
def change
create_table :permissions_roles, id: false do |t|
t.belongs_to :permissions
t.belongs_to :roles
end
end
end
And that leeds to following schema.rb which looks exactly the same in my sql database:
create_table "permissions", force: true do |t|
t.string "subject_class"
t.string "subject_id"
t.string "action"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "permissions_roles", id: false, force: true do |t|
t.integer "permissions_id"
t.integer "roles_id"
end
create_table "roles", force: true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
Now when I call Roles.first.permissions I got following error message:
irb(main):001:0> Role.first.permissions
←[1m←[36mSQL (1.0ms)←[0m ←[1mUSE [rails_confreport_develop]←[0m
←[1m←[35mRole Load (2.0ms)←[0m EXEC sp_executesql N'SELECT TOP (1) [roles].* FROM [roles] ORDER BY [roles].[id] ASC'
RuntimeError: Unknown bind columns. We can account for this.
Same happens if I call Permission.first.roles! What am I missing?
Best regards!
The mistake was the spelling of the foreign keys in my joined-table.
Changed this:
create_table "permissions_roles", id: false, force: true do |t|
t.integer "permissions_id"
t.integer "roles_id"
end
to this:
create_table "permissions_roles", id: false, force: true do |t|
t.integer "permission_id"
t.integer "role_id"
end
And it works.
I am trying to build my database from scratch.
I have run the rake db:reset and rake db:migrate
I have edited my CreatePerformances migration not to include the filed 'file_name' (I usually would create a new migration but its a small project)
class CreatePerformances < ActiveRecord::Migration
def change
create_table :performances do |t|
t.date :date
t.string :location
t.timestamps
end
end
end
When i look at my schema.rb file it still includes the file_name field
.
.
.
create_table "performances", force: true do |t|
t.string "file_name"
t.date "date"
t.string "location"
t.datetime "created_at"
t.datetime "updated_at"
end
what am i doing wrong?
For my projects table I have a column, state, which take string values: "open", "in production", "pending approval" and "completed". The actions that trigger changes between these states are messages that go to and from users about the projects or actions associated to messages. When the object, project, goes from "open" to "in production", in the users inbox a user has a button appearing on the conversation associated with the project that reads, "Drop Project." Moreover, I can wire up the functionality as well. Clicking this button will disassociate you with the project.
My question: how can I have this button hide itself or disappear after 5 days of the project's state, having gone from "open" to "in production"? In other words, I want the user to have the opportunity to disassociates his self from the project within a certain time limit. After that, he is stuck with the project and is encouraged to finish it.
Also, how would I test this with rspec? Is this strictly with an integration test, or can I test it with a unit test too?
I am aware of this SO post (Rails 3 Check if attribute changed), but it has not helped me figure out the solution to my problem. However, I feel like it could serve as support.
Here is my db schema and models:
ActiveRecord::Schema.define(version: 20140514191454) do
create_table "conversations", force: true do |t|
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_id"
end
create_table "organizations", force: true do |t|
t.string "name"
t.datetime "ruling_year"
t.text "mission_statement"
t.string "guidestar_membership"
t.string "ein"
t.string "street1"
t.string "street2"
t.string "city"
t.integer "state_id"
t.string "zip"
t.integer "ntee_major_category_id"
t.string "funding_method"
t.integer "user_id"
t.string "cause"
end
create_table "private_messages", force: true do |t|
t.integer "sender_id"
t.integer "recipient_id"
t.string "subject"
t.text "body"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "project_id"
t.integer "conversation_id"
end
create_table "project_users", force: true do |t|
t.integer "user_id"
t.integer "project_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "projects", force: true do |t|
t.string "title"
t.text "description"
t.string "skills"
t.string "causes"
t.datetime "deadline"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_id"
t.integer "organization_id"
t.integer "estimated_hours"
t.string "state"
end
create_table "user_conversations", force: true do |t|
t.integer "user_id"
t.integer "conversation_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "users", force: true do |t|
t.integer "organization_id"
t.string "first_name"
t.string "last_name"
t.string "email"
t.string "interests"
t.string "skills"
t.string "street1"
t.string "street2"
t.string "city"
t.integer "state_id"
t.integer "phone_number"
t.string "zip"
t.boolean "organization_administrator"
t.boolean "organization_staff"
t.boolean "volunteer"
t.datetime "created_at"
t.datetime "updated_at"
t.string "password_digest"
t.string "position"
t.integer "project_id"
t.string "time_zone"
end
end
Conversation
class Conversation < ActiveRecord::Base
has_many :private_messages, -> {order('created_at ASC')}
def sender_user_name_of_recent_message
message = self.private_messages.last
user = message.sender_id
name = User.find_by(id: user)
"#{name.first_name} #{name.last_name}"
end
def the_id_of_sender
message = self.private_messages.last
user = message.sender_id
name = User.find_by(id: user)
name.id
end
def private_message_subject
message = self.private_messages.last
message_subject = message.subject
end
def private_message_body
message = self.private_messages.last
message_body = message.body
end
def join_request
message = self.private_messages.first
project = Project.find_by(id: message.project_id)
if project
project.state == "open"
end
end
def project_complete_request
message = self.private_messages.first
project = Project.find_by(id: message.project_id)
if project
project.state == "pending approval"
end
end
def opportunity_drop_project
message = self.private_messages.first
project = Project.find_by(id: message.project_id)
if project
project.state == "in production"
end
end
end
User
class User < ActiveRecord::Base
has_secure_password validations: false
belongs_to :organization
belongs_to :project
has_many :project_users
has_many :projects, through: :project_users
has_many :sent_messages, class_name: 'PrivateMessage', foreign_key: 'sender_id'
has_many :received_messages, -> {order('created_at DESC')}, class_name: 'PrivateMessage', foreign_key: 'recipient_id'
has_many :conversations
def private_messages
messages = self.sent_messages + self.received_messages
messages.sort!
end
def user_conversations
collection = self.received_messages.select(:conversation_id).distinct
all_conversations = collection.map do |member|
convo_id = member.conversation_id
Conversation.find_by(id: convo_id)
end
all_conversations.sort
end
def organization_name
organization.name
end
end
Organization
class Organization < ActiveRecord::Base
belongs_to :organization_administrator, foreign_key: 'user_id', class_name: 'User'
has_many :projects
has_many :users
end
PrivateMessage
class PrivateMessage < ActiveRecord::Base
belongs_to :recipient, foreign_key: 'recipient_id', class_name: 'User'
belongs_to :sender, foreign_key: 'sender_id', class_name: 'User'
belongs_to :conversation
validates_presence_of :subject, :body
end
Project
class Project < ActiveRecord::Base
belongs_to :organization
has_many :project_users
has_many :users, through: :project_users
def project_admin
organization.organization_administrator
User.find(organization.organization_administrator.id)
end
def open
self.state == "open"
end
end
ProjectUser
class ProjectUser < ActiveRecord::Base
belongs_to :user
belongs_to :project
end
I don't think there is a built-in Rails way to do this. ActiveModel::Dirty won't work because it only tells you if an object attribute has been changed in memory, once the object is saved to the DB it isn't dirty anymore. I think you'll just have to create a timestamp companion column for state and reset that value to the current time every time you change state. Then you'd just check against the time difference between now and the state_changed attribute.
You can do this by assigning Time.now to the state_changed attribute every time you assign a new state. Or, alternately, you could use a before_save callback on the project object. Use AM::Dirty to check if project.state has been changed, and set the state_changed attribute to Time.now if it has been. That way would be more DRY.
And then in the code for the actions you want time dependent you'd wrap them in a conditional like
if project.state == "in production" && project.state_changed < 5.days.ago
And you'd also create a helper for your views that made the same calculation and only show the button if it is true.
I was missing some large objects here. A user has many projects through volunteer applications and a user has many projects through contracts.
Seeing as that accepting a user's solicitation on a project occurs in the user's inbox which contains an array of conversations that have a foreign key, contract_id, I implemented the following method in the Conversation model:
def with_opportunity_to_drop_job
contract = Contract.find(self.contract_id)
contract.active && contract.work_submitted == false && contract.created_at > 5.days.ago
end
If the creation date is more than 5 days ago, the button disappears -- luckily I have tests that validate this so I do not need to wait around for 5 days :-)