HABTM not working - unknown bind - ruby-on-rails-4

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.

Related

Unable to update attribute value in Rails

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

how to Create devise for existing table

I'm creating web application in Ruby on rails.I have a User model created already.
Now i want create Devise to log in.
My existing dashboard_user table is
class CreateDashboardUsers < ActiveRecord::Migration
def change
create_table :dashboard_users ,id:false do |t|
t.primary_key :USER_ID
t.string :USER_NAME
t.string :NORMALIZED_USER_NAME
t.string :PASSWORD
t.string :LAST_NAME
t.string :FIRST_NAME
t.string :MIDDLE_NAME
t.string :PHONE
t.string :EMAIL_ID
t.integer :SEQ_QUES_ID
t.string :SEQ_QUES_ANSWER
t.string :EXPIRE_PASSWORD_IND
t.date :EXPIRE_PASSWORD_DATE
t.string :DEACTIVATED_IND
t.date :DEACTIVATED_DATE
t.integer :ROLE_ID
t.string :CREATED_BY
t.string :UPDATED_BY
t.timestamps
end
end
end

Carrierwave is not handling file upload when AR backed object is updated

Can the update action in rails handle file uploads with Carrierwave? After completing the action I cannot find a record of the 'uploaded' image any where. In rails console, I call, user.small_cover, and the following is returned which does not look satisfactory: #, #mounted_as=:small_cover>
My update action is fairly large so I will only show the important slice
...
elsif a_nonprofit_staff_member_updates_profile?(organization)
#user.update_columns(user_params)
flash[:notice] = "You have updated your profile successfully."
redirect_to user_path(#user.id)
...
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password,
:organization_id, :bio, :skills, :interests, :position, :user_group, :contact_reason,
small_cover: [:original_filename] )
end
I tried just using, :small_cover, as the attribute but got an error, no Name method for Nil object, which was very strange to me seeing as that the object was not nil and I was not calling a, name, method. Am I packaging the submitted parameters correctly?
How does one upload a file successfully using carrierwave when the action is updating and not creating an AR backed object in rails? Am I handling the parameters incorrectly
UPDATE:
Here is the relevant code for my user model and my uploader
class User < ActiveRecord::Base
has_secure_password validations: false
belongs_to :organization
has_one :administrated_organization, foreign_key: 'user_id', class_name: 'Organization'
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 :administrated_projects, through: :administrated_organization, source: :projects
has_many :volunteer_requests, class_name: 'VolunteerApplication', foreign_key: 'administrator_id'
has_many :projects, through: :volunteer_applications, source: :administrator
has_many :delegated_projects, class_name: "Contract", foreign_key: 'contractor_id'
has_many :projects, through: :contracts, source: :contractor
has_many :requests_to_volunteer, class_name: 'VolunteerApplication', foreign_key: 'applicant_id'
has_many :projects, through: :volunteer_applications, source: :applicant
has_many :assignments, class_name: "Contract", foreign_key: 'volunteer_id'
has_many :projects, through: :contracts, source: :volunteer
has_many :questions
validates_presence_of :email, :password, :first_name, :last_name, :user_group
validates_uniqueness_of :email
mount_uploader :small_cover, SmallCoverUploader
before_create :generate_token
end
class SmallCoverUploader < CarrierWave::Uploader::Base
end
Schema:
ActiveRecord::Schema.define(version: 20140619170102) do
create_table "contracts", force: true do |t|
t.integer "contractor_id"
t.integer "volunteer_id"
t.boolean "active"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "project_id"
t.boolean "dropped_out"
t.boolean "complete"
t.boolean "incomplete"
t.boolean "work_submitted"
end
create_table "conversations", force: true do |t|
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_id"
t.integer "volunteer_application_id"
t.integer "contract_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"
t.string "state_abbreviation"
t.text "goal"
t.string "contact_number"
t.string "contact_email"
t.string "budget"
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 "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 "questions", force: true do |t|
t.integer "user_id"
t.string "title"
t.text "description"
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"
t.text "bio"
t.string "contact_reason"
t.string "organization_role"
t.boolean "nonprofit"
t.string "type"
t.string "user_group"
t.string "state_abbreviation"
t.string "new_password_token"
t.integer "profile_progress_status"
t.string "small_cover"
end
create_table "volunteer_applications", force: true do |t|
t.integer "user_id"
t.integer "project_id"
t.boolean "accepted"
t.boolean "rejected"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "applicant_id"
t.integer "administrator_id"
end
end
Uploader
class SmallCoverUploader < CarrierWave::Uploader::Base
end
You should try separately with something like:
#user.small_cover.update(cover_params)
I guess your association is belongs_to :small_cover
You'll need to user a second strong parameter method (here called cover_params). That means you'll need to adapt params.
I just want to make an update here, and I am happy to clarify if my brief answer does not satisfy the reader's curiosity.
I basically just used cloudinary and attachinary. This combo works like a dream. Goodbye Carrierwave!

fields_for a nested resource not working

I have the following associations:
class Campaign < ActiveRecord::Base
has_many :events
end
class Event < ActiveRecord::Base
belongs_to :campaign
belongs_to :venue
accepts_nested_attributes_for :venue
end
class Venue < ActiveRecord::Base
has_many :events
end
And I have the following form:
<%= form_for([#campaign, #event]) do |f| %>
<%= f.fields_for :venue do |v| %>
<%= v.text_field :search %>
<% end %>
<% end %>
Anything in the fields_for block is not showing up. But the funny thing is if i change f.fields_for :venue to f.fields_for :venues, the :search field shows up.
But :venues shouldn't be plural on :events. Even in rails console Event.venues does not work
NoMethodError: undefined method `venues'
It also generates the wrong field names
This makes me think I have my model associations jacked up, but after reviewing the docs. it does not seem so. Here is my schema for reference:
create_table "campaigns", force: true do |t|
t.integer "user_id"
t.string "title"
t.text "description"
t.integer "image_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "events", force: true do |t|
t.integer "campaign_id"
t.datetime "start_date"
t.datetime "end_date"
t.integer "venue_id"
t.integer "image_id"
t.datetime "created_at"
t.datetime "updated_at"
t.string "title"
t.text "description"
end
create_table "venues", force: true do |t|
t.float "latitude"
t.float "longitude"
t.string "address1"
t.string "address2"
t.string "city"
t.string "zip"
t.string "state"
t.string "country"
t.string "name"
t.string "gid"
t.datetime "created_at"
t.datetime "updated_at"
end
See the similar SO Posts
1.Does accepts_nested_attributes_for work with belongs_to?
2.Getting fields_for and accepts_nested_attributes_for to work with a belongs_to relationship
As mentioned in one of those posts,one way of achieving it is changing the accepts_nested_attributes_for to the has_many side
class Campaign < ActiveRecord::Base
has_many :events
accepts_nested_attributes_for :events
end
class Event < ActiveRecord::Base
belongs_to :campaign
belongs_to :venue
end
class Venue < ActiveRecord::Base
has_many :events
accepts_nested_attributes_for :events
end
If it is not,you might want to build a venue for events with #event.build_venue in the controller before calling fields_for.
Hope it helps!

How do I hide from a user the ability to perform an action on a resource after a period of time in Rails 4?

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 :-)