I have this code for creating a topic and post in a forum application in Rails 3.1:
def create
#topic = Topic.new(:name => params[:topic][:name], :last_post_at => Time.now)
#topic.forum_id = params[:topic][:forum_id]
#topic.user = current_user
if #topic.save
#post = Post.new(:content => params[:post][:content])
#post.topic = #topic
#post.user = current_user
#post.save!
...
When posting to the create method via the corresponding form, the topic and the post are created and both save calls are successful.
When I call the create method via a functional test, the topic is saved but the post has validation errors.
ActiveRecord::RecordInvalid: Validation failed:
app/controllers/topics_controller.rb:23:in `create'
test/functional/topics_controller_test.rb:26:in `block in <class:TopicsControllerTest>'
The test looks like this:
test "should create topic" do
post :create, :topic => {:name => "New topic", :forum_id => forums(:one).id}, :post => {:content => "Post content"}
end
(current_user is logged in via a setup method.)
When I display the errors of the post object via the debugger or with #post.errors.full_messages, the error array is empty.
The Post model looks like this:
class Post < ActiveRecord::Base
attr_accessible :content
belongs_to :topic
belongs_to :user
end
And the Topic model:
class Topic < ActiveRecord::Base
belongs_to :user
belongs_to :last_poster, class_name: 'User'
attr_accessible :name, :last_poster_id, :last_post_at
belongs_to :forum
has_many :posts, :dependent => :destroy
end
How can I find out what is causing the validation error?
The problem was that I used mocha's Post.any_instance.stubs(:valid?).returns(false) in a test that was executed before my failing test.
Apparently, you have to restore the original behavior before proceeding with other tests by calling Post.any_instance.unstub(:valid?).
Related
I have 3 models of User, Role and UserRole with their respective controllers as UsersController, RolesController and UserRolesController.
I have a method in the UserRoles controller which I would want to access through the Users controller but I keep having errors as explained below.
I have tried various means of even moving the method def self.add_roles_to_user(user, role) from the UsersRoles controller into the UserRole model and call it but I keep having the same error.
I have gone through lots of similar questions and various blogs, including those on this platform such as Calling a method from controller, and others but to no good results.
class UserRole < ApplicationRecord
# many-to-many association using join table with roles and user
belongs_to :user, inverse_of: :user_roles
belongs_to :role, optional: true, inverse_of: :user_roles
end
class User < ApplicationRecord
has_many :user_roles, inverse_of: :user
has_many :roles, through: :user_roles
end
class Role < ApplicationRecord
# table associations between role and user
has_many :user_roles, inverse_of: :role
has_many :users, through: :user_roles
end
class UserRolesController < ApplicationController
def self.add_roles_to_user(user, role)
if ! user.nil?
if role.length > 0
role.each do |sel_role|
#u_role = UserRole.new
#u_role.user_id = user_id
#u_role.role_id = sel_role.role_id
#u_role.save
end
end
end
end
end
class Users::RegistrationsController < Devise::RegistrationsController
def create_user
respond_to do |format|
if #user.save
# add roles
UserRoles.add_user_roles(params[:user], params[:role])
end
end
end
end
I am calling the add_uer_to_role method in the User controller when I am adding or creating a new user.
What I have noticed is that I keep getting different errors based on how I call the method.
For example, I expect to have no errors when I call the method like; UserRoles.add_roles_to_user(params[:user], params[:role]) but it gives the error NameError (uninitialized constant Users::RegistrationsController::UserRoles):
Hoping a good samaritan will come to my aid as soon as possible. Thanks in advance
If it is a common function, you can define it in application controller and call it. Else you can define in helper.
Please verify Calling a method from another controller
You can use that function as a module and use it:
# lib/common_stuff.rb
module CommonStuff
def common_thing
# code
end
end
# app/controllers/my_controller.rb
require 'common_stuff'
class MyController < ApplicationController
include CommonStuff
# has access to common_thing
end
I have standalone Ruby application and want to use it with active record gem. I've made 3 models:
user.rb
require 'active_record'
class User < ActiveRecord::Base
has_many :posts, :dependent => :destroy
has_many :comments
validates :name, :presence => true
attr_accessible :name, :state
end
post.rb
require 'active_record'
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments
validates :title, :length => { :in => 6..40 }
attr_accessible :title, :content
end
comment.rb
require 'active_record'
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :post
validates :content, :presence => true
attr_accessible :content, :user_id
end
Now I want to populate database with one user, one post and one comment for this post and user by issuing this code:
require 'active_record'
require 'sqlite3'
require './models/user'
require './models/post'
require './models/comment'
ActiveRecord::Base.configurations = YAML::load(IO.read('config/database.yml'))
ActiveRecord::Base.establish_connection("development")
user1 = User.create name: "Joe", state: "England"
post1 = user1.posts.create title: "RoR introduction", content: "RoR intro."
comment1 = post1.comments.create content: "This is great article!"
But now it populates database but user_id is null. What am I missing here?
I think that your comment gets associated with a post, and not a user ...
just say do comment1.user = user1 and then comment1.save!
I think the key issue here is that the user making the comment is not necessarily the user who made the original post. If that were the case you could enforce it via the through option. However since a post may be commented upon by any user, then saying post1.comments.create etc. shouldn't automatically pull in the user who created the post right? Since it might be another user ...
I'm not sure but I don't think you want those attr_accessible specifications in an active record class - I think they are interfering with the fields that active record provides automatically - try removing all of them
Given
User:
class User < ActiveRecord::Base
has_many :discussions
has_many :posts
end
Discussions:
class Discussion < ActiveRecord::Base
belongs_to :user
has_many :posts
end
Posts:
class Post < ActiveRecord::Base
belongs_to :user
belongs_to :discussion
end
I am currently initializing Posts in the controller via
#post = current_user.posts.build(params[:post])
My question is, how do I set/save/edit the #post model such that the relationship between the post and the discussion is also set?
Save and edit discussions along with post
Existing Discussion
To associate the post you're building with an existing discussion, just merge the id into the post params
#post = current_user.posts.build(
params[:post].merge(
:discussion_id => existing_discussion.id
)
You will have to have a hidden input for discussion id in the form for #post so the association gets saved.
New Discussion
If you want to build a new discussion along with every post and manage its attributes via the form, use accepts_nested_attributes
class Post < ActiveRecord::Base
belongs_to :user
belongs_to :discussion
accepts_nested_attributes_for :discussion
end
You then have to build the discussion in the controller with build_discussion after you built the post
#post.build_discussion
And in your form, you can include nested fields for discussions
form_for #post do |f|
f.fields_for :discussion do |df|
...etc
This will create a discussion along with the post. For more on nested attributes, watch this excellent railscast
Better Relations
Furthermore, you can use the :through option of the has_many association for a more consistent relational setup:
class User < ActiveRecord::Base
has_many :posts
has_many :discussions, :through => :posts, :source => :discussion
end
class Discussion < ActiveRecord::Base
has_many :posts
end
class Post < ActiveRecord::Base
belongs_to :user
belongs_to :discussion
end
Like this, the relation of the user to the discussion is maintained only in the Post model, and not in two places.
hi im new in ROR development im just wondering why my app rise a
"undefined method `menu'
i seems to associate my models right
i would like to show a menu that the reservation reserverd and show its recipes inside that menu but it rises undefiend method 'menu'
package_line_item.rb
belongs_to :menu
belongs_to :reservation
reservation.rb
has_one :reservation_package
belongs_to :service
has_many :reservation_function_rooms
has_many :package_line_items
has_many :menus , :through => :package_line_items, :uniq => true
has_many :function_rooms, :through =>:reservation_function_rooms
menu.rb
has_many :package_line_items
has_many :menu_recipes
has_many :recipes, :through => :menu_recipes, :uniq => true
belongs_to :menu_category
package_line_item_controller.rb
def index
#package_line_items = PackageLineItems.all
end
def show
#reservation = Reservation.includes(:package_line_items => :menu).find(params[:id])
end
def new
#reservation = Reservation.find(params[:reservation_id])
#package_line_item = #reservation.package_line_items.build
end
def create
#reservation = Reservation.find(params[:reservation_id])
#reservation.package_line_items.build(params[:package_line_item])
if #package_line_item.save
redirect_to #reservation ,:notice => "added menu"
end
routes.rb
resources :services
resources :reservations do
resources :reservation_packages
resources :reservation_function_rooms
resources :packages
resources :package_line_items
resources :package_crews
end
resources :function_rooms
resources :crews
resources :menu_categories
resources :menus do
resources :menu_recipes
end
ActiveAdmin.routes(self)
devise_for :admin_users, ActiveAdmin::Devise.config
resources :recipe_categories
resources :recipes
package_line_item/show.html.erb
<p id="notice"><%= notice %></p>
<%= #reservation.package_line_items.menu.name%>
if other file is needed feel free to ask me thank you more power to us thanks
It might be because "menu" is a method in the ActiveAdmin DSL. I had a problem with a model called "Page" precisely for this reason. Try renaming your model and see what happens.
I am trying to create a query that finds all the Posts that belong to the same Topic id. I believe I'm on the right track, but all #posts returns is every post in the database.
Topics controller:
def show
#topic = Topic.find(params[:id])
#title = #topic.name
#posts = Post.where('topic' == #topic).order("updated_at").page(params[:page]).per(10) #not working. still just fetches all posts
respond_with(#posts)
end
Topic model:
class Topic < ActiveRecord::Base
has_many :posts, :dependent => :destroy
attr_accessible :name
end
Post model:
class Post < ActiveRecord::Base
belongs_to :topic, :touch => true
accepts_nested_attributes_for :topic
attr_accessible :name, :title, :content, :topic, :topic_attributes
end
I would recommend you to use the association in the model to get all the posts. you could do it like this:
def show
#topic = Topic.find(params[:id])
#title = #topic.name
#posts = #topic.posts.order("updated_at").page(params[:page]).per(10)
respond_with(#posts)
end
You can use the ActiveRecord association to do this:
def show
#topic = Topic.find(params[:id])
#title = #topic.name
#posts = #topic.posts
respond_with(#posts)
end
And if you are going to use 'where' you should use it like this:
Post.where('topic_id' => #topic.id)
This is because topic refers to the activerecord association. But how its stored in the db level is different.
whats inside where is 'almost' sql.