rails3 is not adding the 2nd id to my table - ruby-on-rails-3

the problem I'm having is company_id is not been save to the details table
I know the company_id is there I check it using <%= debug(params[:id])%> on the form before adding all company details information but for some reason is saving everything else but the company_id
##user.rb
has_one :company
##company.rb
belongs_to :user
has_one :detail
##detail.rb
belongs_to :user
##details controller
def new
#detail = Detail.new
user_id = session[:user_id]
company_id = params[:id]
end
def create
#detail = Detail.new(params[:detail])
#detail.user_id = session[:user_id]
#detail.company_id = params[:id]
end
###settings.html.erb
### this is where i make sure that company_id gets pass with the url
link_to 'New Detail', {:controller => 'details', :action =>'new', :id => company.id }, :class => 'plus'
#####routes
resources :details
resources :companies
resources :users
resources :sessions
I know this may not look pretty or proper if you know a better way please let me know...thanks in advance.

I notice something immediately. You may need to fix your associations first. Assuming, a user has one company and a company has one detail.
##user.rb
has_one :company
##company.rb
belongs_to :user
has_one :detail
##detail.rb
belongs_to :user
Should be:
##user.rb
has_one :company
##company.rb
belongs_to :user
has_one :detail
##detail.rb
belongs_to :company
Although, depending on your domain requirements. I would normally have it as: User has_many Companies. And since details is 1:1 with company, I would include all the details inside company.

I didn't realize this until later but I need it pass values to from on the view to the from like so
<% #companies.each do |company| %>
<%= link_to 'New Detail', {:controller =>'details', :action => 'new', :company_id => company.id}, :class => 'plus' %>
<% end %>
and I need it to collect that value on the from...like so
<%= form_for(:detail, :url =>{:action => 'create', :company_id => #company.id}) do |f| %>
...(values)
<% end %>

Related

Rails: multi level nested Forms (accepts nested attributes)

I am creating simple blog level application. below are my models.
class User < ActiveRecord::Base
attr_accessible :name,:posts_count,:posts_attributes , :comments_attributes
has_many :posts
has_many :comments
accepts_nested_attributes_for :posts , :reject_if => proc{|post| post['name'].blank?} , :allow_destroy => true
end
class Post < ActiveRecord::Base
attr_accessible :name, :user_id ,:comments_attributes
belongs_to :user
has_many :comments
accepts_nested_attributes_for :comments
end
class Comment < ActiveRecord::Base
attr_accessible :content, :post_id, :user_id
belongs_to :user
belongs_to :post
end
I am trying to create user,post and comment in one form by using accepts_nested_attributes_for feature of rails. Below is my controller and view code.
Controller-----------
class UsersController < ApplicationController
def new
#user = User.new
#post = #user.posts.build
#post.comments.build
end
def create
#user = User.new(params[:user])
#user.save
end
end
Form----------
<%= form_for #user do |f| %>
<%= f.text_field :name %>
<%= f.fields_for :posts do |users_post| %>
<br>Post
<%= users_post.text_field :name %>
<%= users_post.fields_for :comments do |comment| %>
<%= comment.text_field :content %>
<% end %>
<% end %>
<%= f.submit %>
<% end %>
With the above code i am successfully able to create new user,post and comment but the problem is that i am not able to assign newly created user to newly created comment.when i checked the newly created comment into the database i got below result.I am getting user_id field value of "nil".
#<Comment id: 4, user_id: nil, post_id: 14, content: "c", created_at: "2014-05-30 09:51:53", updated_at: "2014-05-30 09:51:53">
So I just want to know how we can assign newly created comment to newly created user???
Thanks,
You will have to explicitly assign user_id for comments! You are nesting comments under posts, so comments would be having post_id assigned by default but though you are nesting comments under user form indirectly, there is no direct nesting of comments under user, so user_id remains blank in comments.
Try writing after create callback in Comment model to set user_id
In comment.rb
after_create{|comment|
comment.user_id = post.user_id
comment.save
}
Hope this helps :)

Limiting how often a user can post on a particular person's profile/wall in Rails

How can I limit a user to only to being able to post once or twice per day on a particular users's wall? I primarily want to do it in order to limit spam. My code for the wall, models, view, and controllers are below. I don't really know how to go about it as I'm new to rails but I know there is something time.now. I'm not exactly sure how to implement such a feature.
Class UsersController < ApplicationController
def show
#user = User.find(params[:id])
#first_name = #user.first_name
#last_name = #user.last_name
#wallpost = WallPost.new(params[:wall_post])
#showwallposts = #user.received_wallposts
end
def create
#wallpost = WallPost.create(params[:wall_post])
end
models
class WallPost < ActiveRecord::Base
attr_accessible :content, :receiver_id, :sender_id
belongs_to :receiver, :class_name => "User", :foreign_key => "receiver_id"
belongs_to :sender, :class_name => "User", :foreign_key => "sender_id"
end
class User < ActiveRecord::Base
has_many :sent_wallposts, :class_name => 'WallPost', :foreign_key => 'sender_id'
has_many :received_wallposts, :class_name =>'WallPost', :foreign_key => 'receiver_id'
in the view
<%= form_for(#wallpost, :url => {:action => 'create'}) do |f| %>
<%= f.hidden_field :receiver_id, :value => #user.id %>
<%= f.hidden_field :sender_id, :value => current_user.id %>
<%= f.text_area :content, :class => 'inputbox' %>
<%= f.submit 'Post', class: 'right btn' %>
<% end %>
You could create a custom validator which assures maximum DAILY_LIMIT posts have been created on that person's wall that day by that user:
class SpamValidator < ActiveModel::Validator
DAILY_LIMIT = 2
def validate(record)
if similar_posts_today(record).count >= DAILY_LIMIT
record.errors[:spam_limit] << 'Too many posts today!'
end
end
def similar_posts_today(record)
WallPost.where(receiver: record.receiver, sender: record.sender)
.where("DATE(created_at) = DATE(:now)", now: Time.now)
end
end
Then add that validation to your WallPost model:
validates_with SpamValidator
Then it will fail with a validation error when trying to create a wall post beyond the limit set in the constant. You need to handle this case in the create action in your controller. A simple (but not optimal in terms of user experience) way of handling this is:
def create
#wallpost = WallPost.new(params[:wall_post])
flash[:error] = "You've reached the daily posting limit on that wall." unless #wallpost.save
redirect_to user_path(#wallpost.receiver)
end
With that, it'll try to save the new wall post, if it is unable to, it'll set flash[:error] to the error message above. You'd need to show this on your show.html.erb page with <%= flash[:error] if flash[:error] %>.

Rails 3 current user id to comments?

So Im working on a rails app where users can comment on photos or videos another user has uploaded and so far everything is great except I am not able to get the current user_id associated with the person who has commented on the post. This is what I have so far.
user.rb
has_many :comments, :dependent => :destroy
photo.rb
has_many :comments, :as => :commentable
video.rb
has_many :comments, :as => :commentable
comments_controller.rb
def create
#commentable = find_commentable
#comment = #commentable.comments.build(params[:comment])
if #comment.save
redirect_to :id => nil, :notice => "Successfully created comment."
else
render :action => 'new'
end
end
How can I get the user id to appear with the current comments? I have the comment type and comment id I am just looking for a way to have it so the user_id can appear. Any suggestions?
You should add a hidden_field to your form partial where you store the current_user.id
something like:
<%= f.hidden_field :user_id, :value => current_user.id %>
of course you should have a field user_id in your comment model, as a comment belongs_to user and a user has_many comments.
update:
what ofca pointed out, this can approach can lead to security issues as the hidden field could be modified by the user in the browser, e.g. using firebug.
In this case it is probably better to to leave out this field in the view and create the comment in the controller by using
<%= current_user.comments.create(params[:comment]) %>
The way you have it now, it is only set up one way.
Plus you have to make it polymorphic
try adding:
comment.rb
belongs_to :user
belongs_to :commentable, :polymorphic => true

saving record to join table Has_many :through

I am new to Rails 3 and having trouble with saving records in the Join table. I have been looking around and trying different examples found on this website and from the documentation or books, but I don't understand why I can't get it to work. I am trying to create Authorization by creating Roles and associate them to users. So far I have been trying to assign roles from the update action in the Users controller without prevail.
I have 3 models: the User.rb, role.rb, and assignment.rb (the join table)
class User < ActiveRecord::Base
has_many :assignments, :dependent => :destroy
has_many :roles, :through => :assignments, :foreign_key => :role_id
accepts_nested_attributes_for :roles
attr_accessor :password, :role_ids
attr_accessible :first_name, :last_name, :email, :password, :password_confirmation, :status, :description, :username, :roles_attributes
...
end
class Role < ActiveRecord::Base
has_many :assignments
has_many :users, :through => :assignments, :foreign_key => :user_id
accepts_nested_attributes_for :users
attr_accessible :name
end
class Assignment < ActiveRecord::Base
belongs_to :user
belongs_to :role
accepts_nested_attributes_for :roles
end
The Users controller in the update action I have the following
class UsersController < ApplicationController
...
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:user])
#user.roles.build
flash[:success] = "Profile updated"
redirect_to #user
else
#title = "Edit" + " " + #user.username
render 'edit'
end
end
...
end
and in the 'edit' view page I intend to have checkboxes to update the User record with an associated role:
EDIT: Changed the "check_box" with "check_box_tag" ... the check boxes appear properly, but the values are not saved.
<%= form_for(#user) do |f| %>
...
<div class="field">
<%= f.label :roles %><br />
<%= f.fields_for :role_ids do |r| %>
<% #roles.each do |role| %>
<%= check_box_tag "user[roles][]", role.id, #user.roles.include?(role.id) %>
<%= role.name %>
<% end %>
<%= hidden_field_tag "user[roles][]", "" %>
<% end %>
</div>
<% end %>
With this code I even get an error where 'Roles' have no association.
EDIT: this was corrected with the accepts_nested_attributes_for :role. Thanks!
No association found for name `roles'. Has it been defined yet?
I am really confused where I am doing something wrong. Your help would be much appreciated.
Aurelien
You have to use the same name with "accepts_nested_attributes_for" as you used defining the association:
class Assignment < ActiveRecord::Base
belongs_to :user
belongs_to :role
accepts_nested_attributes_for :role
end
Finally solved the problems and thought I could share.
The models associations but I did change the attr_accessible:
class User < ActiveRecord::Base
has_many :assignments, :dependent => :destroy
has_many :roles, :through => :assignments, :foreign_key => :role_id
accepts_nested_attributes_for :roles
attr_accessor :password
attr_accessible ..., :roles_ids
...
end
In the User controller for the edit and update action.
def edit
#title = "Edit" + " " + #user.username
#roles = Role.find(:all)
#user.assignments.build
end
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:user])
flash[:success] = "Profile updated"
redirect_to #user
else
#title = "Edit" + " " + #user.username
render 'edit'
end
end
The important part was the view part and assigning the right names for the checkbox tags
<%= form_for(#user) do |f| %>
<div class="field">
<%= f.label :roles %><br />
<%= f.fields_for :role_ids do |r| %>
<% #roles.each do |role| %>
<%= check_box_tag "user[role_ids][]", role.id, #user.roles.include?(role) %>
<%= role.name %>
<% end %>
<%= hidden_field_tag "user[role_ids][]", #user.id %>
<% end %>
</div>
The check_box_tag lets the form save an array and gives more control than check_box
Then in order to assign the multiple Role ids, the name of the check_box_tag should include user[roles_ids][].
Finally the last parameter of the check_box_tag returns if the User has already the roles and checks the checkboxes if true.
I must admit that the name part of the check_box_tags is really confusing but it works :).

How to capture a comment's author then display in tooltip?

I have a form attached to profiles where short comments can be submitted. I want to capture the author's name though so I can display it in a tooltip when hovering over the comment's body.
In my create method in the controller I have:
def create
#comment = Comment.new(params[:comment])
#comment.save!
redirect_to profile_path(#comment.profile)
end
Inside my migration:
t.timestamps
t.integer :profile_id
t.string :author_id
t.string :body
Profile model:
belongs_to :user
accepts_nested_attributes_for :user
has_many :comments
Comment model:
belongs_to :profile
ProfilesController:
def show
#user = User.find(params[:id])
#profile = user.profile
#superlative = #profile.superlatives.new
end
And my form:
<%= form_for #comment do |f| %>
<%= f.hidden_field :profile_id, :value => #profile.id %>
<%= f.hidden_field :author_id, :value => "#{current_user.profile.first_name} #{current_user.profile.last_name}" %>
<%= f.text_field :body %>
<%= f.submit 'Add new' %>
<% end %>
I was thinking of linking the :author_id to current_user.profile.id and using that association to display :first_name and :last_name which are attributes of the profile. Or is there a simpler, better way?
UPDATE: I got it to display the name though I'm still curious if there's a better way.
Your solution looks fine, but I'd store the User (or whatever class current_user returns) instead of the Profile:
In app/models/comment.rb:
class Comment < ActiveRecord::Base
belongs_to :profile
belongs_to :author, :class_name => "User", :foreign_key => "author_id"
... rest of the code ...
end
You then change your migration to:
t.integer :author_id
and your controller method to:
def create
#comment = Comment.new(params[:comment].merge(:author_id => current_user.id))
#comment.save!
redirect_to profile_path(#comment.profile)
end
In your view (I used the title attribute do create a tooltip, but feel free to use whatever method you like):
<div class="comment" title="<%= #comment.author.profile.first_name %> <%= #comment.author.profile.last_name %>">
<%= #comment.body %>
</div>
I would suggest something like this:
In your routes.rb create a nested resource for comments
resources :users do
resources :comments
end
In your User model
class User
has_many :comments
end
In your Comment model
class Comment
belongs_to :user
end
In your CommentsController in the new and create methods
#comment = User.find(params[:user_id]).comments.new(params[:comment])
So the comment automagically gets created as belonging to that User and you don't have to pass anything around.
Then, in your Comment view, you could just call its owners name
#comment.user.first_name