This is a follow up question to ActiveRecord having 2 FKs from the same column in a table I am getting the message 'uninitialized constant User::Message' and I don't know what is causing it.
My create action from my Message controller is
def create
#message = current_user.packages.build(message_params)
#message.sender = current_user
#message.receiver = User.find(params[:id])
#message.date = Time.now
if #message.save
flash[:success] = "Message Created!"
else
flash[:danger] = "Message Not Created!"
end
redirect_to user_path
end
I added the controller to my routes.rb file
resources :messages, only: [:create, :destroy]
My action from my User controller is
def show
#user = User.find(params[:id])
#message = #user.messages.build #error is thrown here
#package_feed_items = #user.packages.paginate(page: params[:page],:per_page => 5)
#route_feed_items = #user.routes.paginate(page: params[:page],:per_page => 5)
end
The form is in a partial in my 'messages' folder from the views directory. This is called from a view in my users controller with
<%= render 'messages/create_message_modal' %>
my Message model is now
class Message < ActiveRecord::Base
belongs_to :sender, class_name => :user, foreign_key => 'sender_id'
belongs_to :receiver, class_name => :user, foreign_key => 'receiver_id'
default_scope -> { order('created_at DESC') }
validates :receiver_id, presence: true
validates :sender_id, presence: true
validates :body, presence: true
validates :date, presence: true
state_machine :initial => :unOpened do
state :unOpened, value: "Un-Opened"
state :opened, value: "Opened"
state :deleted, value: "Deleted"
event :open do
transition :unOpened => :opened
end
event :delete do
transition :opened => :deleted
end
end
end
and my user model is
class User < ActiveRecord::Base
... other relations ...
has_many :messages
... validation & state machine ...
end
EDIT
The tail of my log file
Completed 500 Internal Server Error in 8ms
NameError (uninitialized constant User::Message):app/controllers/users_controller.rb:33:in `show'
Rendered /Users/jeff/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-4.0.1/lib/action_dispatch/middleware/templates/rescues/_source.erb (0.4ms)
Rendered /Users/jeff/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-4.0.1/lib/action_dispatch/middleware/templates/rescues/_trace.erb (0.7ms)
Rendered /Users/jeff/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-4.0.1/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (0.8ms)
Rendered /Users/jeff/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-4.0.1/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (11.2ms)
Specify the class_name option to user model like below,
class User < ActiveRecord::Base
has_many :messages, class_name: 'Message'
end
Try this it should work, anyway you need to find why the direct relation is not working.
Related
I can't get rails to update my nested attributes, though regular attributes work fine. This is my structure:
unit.rb:
class Unit < ApplicationRecord
has_many :unit_skill_lists
has_many :skill_lists, through: :unit_skill_lists, inverse_of: :units, autosave: true
accepts_nested_attributes_for :skill_lists, reject_if: :all_blank, allow_destroy: true
end
unit_skill_list.rb:
class UnitSkillList < ApplicationRecord
belongs_to :unit
belongs_to :skill_list
end
skill_list.rb:
class SkillList < ApplicationRecord
has_many :unit_skill_lists
has_many :units, through: :unit_skill_lists, inverse_of: :skill_lists
end
And this is (part of) the controller:
class UnitsController < ApplicationController
def update
#unit = Unit.find(params[:id])
if #unit.update(unit_params)
redirect_to edit_unit_path(#unit), notice: "Unit updated"
else
redirect_to edit_unit_path(#unit), alert: "Unit update failed"
end
end
private
def unit_params
unit_params = params.require(:unit).permit(
...
skill_list_attributes: [:id, :name, :_destroy]
)
unit_params
end
end
The relevant rows in the form (using formtastic and cocoon):
<%= label_tag :skill_lists %>
<%= f.input :skill_lists, :as => :check_boxes, collection: SkillList.where(skill_list_type: :base), class: "inline" %>
Any idea where I'm going wrong? I have tried following all guides I could find but updating does nothing for the nested attributes.
Edit after help from Vasilisa:
This is the error when I try to update a Unit:
ActiveRecord::RecordInvalid (Validation failed: Database must exist):
This is the full unit_skill_list.rb:
class UnitSkillList < ApplicationRecord
belongs_to :unit
belongs_to :skill_list
belongs_to :database
end
There is no input field for "database". It is supposed to be set from a session variable when the unit is updated.
If you look at the server log you'll see something like skill_list_ids: [] in params hash. You don't need accepts_nested_attributes_for :skill_lists, since you don't create new SkillList on Unit create/update. Change permitted params to:
def unit_params
params.require(:unit).permit(
...
skill_list_ids: []
)
end
UPDATE
I think the best options here is to set optional parameter - belongs_to :database, optional: true. And update it in the controller manually.
def update
#unit = Unit.find(params[:id])
if #unit.update(unit_params)
#unit.skill_lists.update_all(database: session[:database])
redirect_to edit_unit_path(#unit), notice: "Unit updated"
else
redirect_to edit_unit_path(#unit), alert: "Unit update failed"
end
end
I am following Ryan Bates railscasts video of friendly url. I am trying to implement that on my Category model by overriding the to_parammethod.
Seems like it's not working, or I am missing something.
Below is my url before overriding:
localhost:3000/search?category_id=1
After overriding the to_param the url remained same.
Following is my code:
Category model
class Category < ActiveRecord::Base
enum status: { inactive: 0, active: 1}
acts_as_nested_set
has_many :equipments, dependent: :destroy
has_many :subs_equipments, :foreign_key => "sub_category_id", :class_name => "Equipment"
has_many :wanted_equipments, dependent: :destroy
has_many :services, dependent: :destroy
validates :name, presence: true
validates_uniqueness_of :name,message: "Category with this name already exists", scope: :parent_id
scope :active, -> { where(status: 1) }
def sub_categories
Category.where(:parent_id=>self.id)
end
def to_param
"#{id} #{name}".parameterize
end
end
Controller
def search_equipments
begin
if (params.keys & ['category_id', 'sub_category', 'manufacturer', 'country', 'state', 'keyword']).present?
if params[:category_id].present?
#category = Category.active.find params[:category_id]
else
#category = Category.active.find params[:sub_category] if params[:sub_category].present?
end
#root_categories = Category.active.roots
#sub_categories = #category.children.active if params[:category_id].present?
#sub_categories ||= {}
Equipment.active.filter(params.slice(:manufacturer, :country, :state, :category_id, :sub_category, :keyword)).order("#{sort_column} #{sort_direction}, created_at desc").page(params[:page]).per(per_page_items)
else
redirect_to root_path
end
rescue Exception => e
redirect_to root_path, :notice => "Something went wrong!"
end
end
route.rb
get "/search" => 'welcome#search_equipments', as: :search_equipments
index.html.erb
The line which is generating the url
<%= search_equipments_path(:category_id => category.id ) %>
You are generating URLs in such a way as to ignore your to_param method. You're explicitly passing a value of only the ID to be used as the :category_id segment of your URLs. If you want to use your to_param-generated ID, then you need to just pass the model to the path helper:
<%= search_equipments_path(category) %>
I'm working on a project where there are tasks that make up a scavenger hunt. When a user creates a new hunt, I'd like the hunts/show.html.erb file to show the hunt as well as the tasks associated with that hunt. But the models are giving me trouble. I've got the hunt model setup to that it accepts nested attributes for the tasks model. So when the user creates a new hunt, she also creates three tasks automatically. I can get the new hunt to save, but I can't get those new tasks to save. Here are my models.
What's missing? Do I need an "attr accessible" statement in the HunTasks.rb file?
class Hunt < ActiveRecord::Base
has_many :hunt_tasks
has_many :tasks, :through => :hunt_tasks
accepts_nested_attributes_for :tasks, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
attr_accessible :name
validates :name, :presence => true,
:length => { :maximum => 50 } ,
:uniqueness => { :case_sensitive => false }
end
class Task < ActiveRecord::Base
has_many :hunt_tasks
has_many :hunts, :through => :hunt_tasks
attr_accessible :name
validates :name, :presence => true,
:length => { :maximum => 50 } ,
:uniqueness => { :case_sensitive => false }
end
class HuntTask < ActiveRecord::Base
belongs_to :hunt # the id for the association is in this table
belongs_to :task
end
Here's what my Hunt controller looks like:
class HuntsController < ApplicationController
def index
#title = "All Hunts"
#hunts = Hunt.paginate(:page => params[:page])
end
def show
#hunt = Hunt.find(params[:id])
#title = #hunt.name
#tasks = #hunt.tasks.paginate(:page => params[:page])
end
def new
if current_user?(nil) then
redirect_to signin_path
else
#hunt = Hunt.new
#title = "New Hunt"
3.times do
hunt = #hunt.tasks.build
end
end
end
def create
#hunt = Hunt.new(params[:hunt])
if #hunt.save
flash[:success] = "Hunt created!"
redirect_to hunts_path
else
#title = "New Hunt"
render 'new'
end
end
....
end
The major difference between your example and the railscast is that you are doing many-to-many instead of one to many (I think his was Survey had many Questions). Based on what you described, I wonder if the HuntTask model is necessary. Are the tasks for one hunt ever going to be resused in another hunt? Assuming they are, then looks like your answer is here:
Rails nested form with has_many :through, how to edit attributes of join model?
You'll have to modify your new action in the controller to do this:
hunt = #hunt.hunt_tasks.build.build_task
Then, you'll need to change your Hunt model to include:
accepts_nested_attributes_for :hunt_tasks
And modify your HuntTask model to include:
accepts_nested_attribues_for :hunt
I have an app I am deploying to Heroku. Everything seems to work besides the "show" action for my User model.
Here is my code for the user model (what's relevant, anyway)
class User < ActiveRecord::Base
attr_accessor :password
attr_accessible :username, :email, :password,
:password_confirmation, :confirmed,
:school_id, :graduation,
:admin, :stars, :credits, :school_name
has_many :uploads, :dependent => :destroy
belongs_to :school
has_many :downloads, :source => :user_id, :dependent => :destroy
has_many :comments, :dependent => :destroy
#VALIDATIONS OMITTED
#WARNING
before_create :encrypt_password
#PASSWORD ENCRYPTION METHOD OMITTED
#getter for school name
def school_name
school.name if school
end
#setter for school name (will create school if it didn't find one)
def school_name=(name)
self.school = School.find_by_name(name) unless name.blank?
end
def add_credits(num)
self.credits += num
end
def charge
self.credits -= 1
self.save(false)
end
def has_downloaded?(file)
#downloads = self.downloads.find(:all, :conditions => "upload_id = #{file.id}")
return (#downloads.length > 0)
end
private
#MORE PASSWORD ENCRYPTION LOGIC
end
Here is the code for my upload model:
class Upload < ActiveRecord::Base
default_scope :order => 'uploads.created_at DESC'
attr_protected :linked_file_name, :linked_content_type, :linked_size
attr_accessible :user_id, :stars, :ratings,
:semester, :professor, :year,
:description, :course_id, :school_id
after_save :set_course_school
belongs_to :user
belongs_to :school
belongs_to :course
has_many :downloads, :source => :upload_id, :dependent => :destroy
has_many :comments, :foreign_key => "file_id", :dependent => :destroy
#belongs_to :class
#paperclip
has_attached_file :linked,
:storage => :s3,
:s3_credentials => "#{RAILS_ROOT}/config/s3.yml",
:path => ":class/:id/:attachment/:basename.:extension"
#validations
validates :school_id, :presence => true
def update_rating
#comments = self.comments.all
if #comments.length > 0
#stars = 0
#comments.each do |comment|
#stars += comment.rating
end
self.stars = #stars
self.ratings = #comments.length
end
self.save(false)
end
def course_name
return [course.subject, course.course_code].join(' ') if course
end
def course_name=(name)
#split = name.split(' ', 2)
#subject = #split.first
#course_code = #split.last
#conditions = {
:subject => #subject,
:course_code => #course_code,
:school_id => self.school_id
}
self.course = Course.find(:first, :conditions => #conditions) || Course.create(#conditions)
end
def set_course_school
course.set_school
end
end
And here is the controller action:
def show
#user = User.find(params[:id])
#uploads = #user.uploads.all
#downloads = #user.downloads.all
end
Heroku seems to be having some problem with the statement #user.uploads.all which works fine locally, here is what the logs give me:
2011-12-29T21:57:07+00:00 app[web.1]: Started GET "/users/1" for 200.88.103.28 at 2011-12-29 13:57:07 -0800
2011-12-29T21:57:07+00:00 app[web.1]: Processing by UsersController#show as HTML
2011-12-29T21:57:07+00:00 app[web.1]: Parameters: {"id"=>"1"}
2011-12-29T21:57:07+00:00 app[web.1]: Completed in 10ms
2011-12-29T21:57:07+00:00 app[web.1]:
2011-12-29T21:57:07+00:00 app[web.1]: ActiveRecord::StatementInvalid (PGError: ERROR: operator does not exist: character varying = integer
2011-12-29T21:57:07+00:00 app[web.1]: : SELECT "uploads".* FROM "uploads" WHERE ("uploads".user_id = 1) ORDER BY uploads.created_at DESC):
2011-12-29T21:57:07+00:00 app[web.1]: ^
2011-12-29T21:57:07+00:00 app[web.1]: app/controllers/users_controller.rb:21:in `show'
2011-12-29T21:57:07+00:00 app[web.1]: HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.
2011-12-29T21:57:07+00:00 app[web.1]: LINE 1: ...ROM "uploads" WHERE ("uploads".user_id = 1) ORDER...
Any ideas? I imagine the fix is super simple. What's weird is that I have another Heroku deployed app that uses the exact same user logic (has a show page that gets all the 'posts' of a user) and that works fine. The code looks almost identical...
I would greatly appreciate a solution to this problem. I wish I could offer a bounty but I used most of my rep on a big bounty on an Android question.
From the error statement, it looks like the user_id column on your uploads table is a varchar, not an integer. Postgres (used by Heroku) doesn't automatically cast, as far as I know.
Can you confirm the data types?
I am working on an app where users' "projects" can follow "plant" objects from the database. I am getting the following error for the create action in my "Prelationships" controller (Plant Relationships that connect Users' projects to fixed "plant" objects) when I hit "Follow" for any number of plant objects in my app:
"You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.[]"
I realize this is a big question, and yes, I'm pretty much a newbie. All the migrations should be fine. I appreciate any help--even if it means suggesting a whole new way of tackling this issue.
Here's what my controller, called "Prelationships", looks like:
class PrelationshipsController < ApplicationController
def create
#plant = Plant.find(params[:prelationship][:pfollowed_id])
#project.follow!(#plant)
respond_to do |format|
format.html { redirect_to #project }
format.js
end
end
end
And my "Prelationships" model:
class Prelationship < ActiveRecord::Base
attr_accessible :pfollowed_id
belongs_to :pfollower, :class_name => "Project"
belongs_to :pfollowed, :class_name => "Plant"
validates :pfollower_id, :presence => true
validates :pfollowed_id, :presence => true
end
And my "Projects" model:
class Project < ActiveRecord::Base
attr_accessible :title, :address, :latitude, :longitude, :state
belongs_to :user
has_many :prelationships, :foreign_key => "pfollower_id",
:dependent => :destroy
has_many :pfollowing, :through => :prelationships, :source => :pfollowed
def pfollowing?(pfollowed)
prelationships.find_by_pfollowed_id(pfollowed)
end
def pfollow!(pfollowed)
prelationships.create!(:pfollowed_id => pfollowed.id)
end
end
And my "plant" model:
class Plant < ActiveRecord::Base
has_many :prelationships, :foreign_key => "pfollowed_id",
:class_name => "Prelationship"
has_many :pfollowers, :through => :reverse_prelationships,
:source => :pfollower
end
And, finally, my "_plants_form" partial for the view:
<%= form_for #project.prelationships.build(:pfollowed_id =>
#project_id) do |f| %>
<%= collection_select(:prelationships, :pfollowed_id, Plant.all, :id, :name,
options = {:prompt => "Select your plants"}, :class => "listselect") %>
<div class="actions"><%= f.submit "Pfollow" %></div>
<% end %>
Here's the error from my log:
Started POST "/prelationships" for 127.0.0.1 at 2011-11-20 23:31:57 +0100
Processing by PrelationshipsController#create as HTML
Parameters: {"utf8"=>"✓",
"authenticity_token"=>"NKqa1f0M2yPLQDHbRLnxl3SiwBeTus/1q1hpZjD7hgY=",
"prelationships"=>{"pfollowed_id"=>"5"}, "commit"=>"Pfollow"}
Completed 500 Internal Server Error in 14ms
NoMethodError (You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.[]):
app/controllers/prelationships_controller.rb:4:in `create'
Rendered /Users/mmelone12/.rvm/gems/ruby-1.9.2-p290/gems/actionpack-
3.0.9/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.4ms)
Rendered /Users/mmelone12/.rvm/gems/ruby-1.9.2-p290/gems/actionpack-
3.0.9/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb
(30.6ms)
Rendered /Users/mmelone12/.rvm/gems/ruby-1.9.2-p290/gems/actionpack-
3.0.9/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within
rescues/layout (37.1ms)
Yep. Like Swanand point out, you should initialize #project object inside :create action. Like #project = Project.find(params[:project_id]) if you do not do it with a before_filter.
If you already instantiated #project before, see what happens when you manually try to retrieve #plant object in Rails console Plant.find(1)