Active record in standalone Ruby - ruby

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

Related

Rails 4 Nested Validations not working

I have this model:
class CompetitionEntry < ActiveRecord::Base
has_many :participants
has_one :address
has_many :music_programs
accepts_nested_attributes_for :address
accepts_nested_attributes_for :participants, :music_programs,
:allow_destroy => true,
:reject_if => :all_blank
end
and this one:
class Participant < ActiveRecord::Base
belongs_to :competition_entry
has_one :birthplace
validates :name, :surname, :instrument, presence: true
end
Now the problem is that, if I create a new competition entry, it goes through.
But if I fill ONE field, i.e name, then it comes up with an error!
Why is this happening? It should fail when all are empty!
When you use accepts_nested_attributes_for, you are able to create the participants records at the same time that the competition_entry record, considering that the hash passed to competition_entry.create contains participants_attributes. When you pass only name, it validates the participant to be created and fail because it has no surname and instrument. When you leave all field empty, the behaviour should be the same, but it isn't because you explicitly set :reject_if => :all_blank.
:reject_if => :all_blank states that the participant_attributes hash should be ignored if it is blank?, which happens when you don't fill any field. What is happening then is that a competition_entry is being created without trying to create a participant because the accepts_nested_attributes_for is just ignored.

Manually updating attributes mounted by Carrierwave Uploader

I am unable to use model.update_attribute on an attribute that is mounted by a carrierwave uploader. The SQL statement wont accept the value and adds NULL to the placeholder. If I remove the mount_uploader statement from the model class it works as normal. I am troubleshooting things from the console and trying to add some attributes while seeding the DB and this is thwarting my efforts. Ideas?
Thanks.
Update:
Relevant code:
class Profile < ActiveRecord::Base
belongs_to :user
has_and_belongs_to_many :sports
has_and_belongs_to_many :interests
has_and_belongs_to_many :minors
has_and_belongs_to_many :majors
has_and_belongs_to_many :events
has_and_belongs_to_many :groups
attr_accessible :description, :username, :avatar, :bio, :first_name, :last_name, :major, :minor, :graduation_date, :living_situation, :phone, :major_ids, :minor_ids, :sport_ids
mount_uploader :avatar, AvatarUploader
end
I am simply trying to rewrite the :avatar string from a db seed file and while testing from the rails console like so:
Profile.first.update_attribute(:avatar, 'foo')
Both work when I comment out the mount_uploader line.
Does adding the mount_uploader method freeze the string or make it immutable?
I found a solution to this.
My issue was that I was not able to alter the attribute mounted my the CarrierWave uploader from my seeds.rb file.
This works:
user.profile.update_column(:avatar, 'foobar/image.png')

"Retweets" with Datamapper

I want to impliment something which is similar to Twitter Repost System, therefore I will use this as an example. So let's say I have a Tweet Model and I want to allow other user to repost a certian tweet of another user, how do I impliment something like this?
I thought I would be a cool idea to put the retweet class into the tweet to be able to acess the repost too when I use Tweet.all to recive all tweets stored in the database, but somehow I didn't worked as expected...
The following Code is just an example which should show how to impliment this even if it is not working...
Any ideas how I could build a working repost model which also allows me to access both tweets and retweet by using Tweet.all?
class Tweet
class Retweet
include DataMapper::Resource
belongs_to :user, key => true
belongs_to :tweet, key => true
end
include DataMapper::Resource
property :text, String
property :timestamp, String
belongs_to :user
end
Important: I should be carrierwave compatible.
class Tweet
include DataMapper::Resource
property :id, Serial
has n, :retweets, 'Tweet', :child_key => :parent_id
belongs_to :parent, 'Tweet', :required => false
belongs_to :user
def is_retweet?
self.parent_id ? true : false
end
end
original = Tweet.create :user => user1
retweet = Tweet.create :parent => original, :user => user2
retweet.is_retweet? # => true

Rails multiple belongs_to assignment

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.

Validation error in test but error array is empty

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?).

Resources