I am working on an application that involves "follow/unfollow" functionality. Users can follow Objects and Objects can have many Users following them. It's a has_many :through relationship via a Relationships model/controller.
I have the following snippet in the object#show view:
<% if current_user.following?(#object) %>
<%= render 'unfollow' %>
<% else %>
<%= render 'follow' %>
<% end %>
When testing various functionalities in a request spec, it shows undefined method 'following?' for nil:NilClass and fails all of the object#show specs.
The following? method is in the User model and looks like this:
def following?(object)
relationships.find_by_object_id(object.id)
end
The method following? is in the User model (since they are the only ones doing following and unfollowing). I thought you could use methods between objects in Ruby, but perhaps not. If not, how would I go about refactoring this to be able to use that method?
Thanks in advance for any help!
There is no current_user helper in specs. That's why you get nil.
You should stab test user into current_user variable
Related
I'm just starting to learn Rails and I'm currently working on a watered down Facebook clone. I'd like to know what exactly my build method that I'm including in my form_for helper is doing. This is taken from The Ruby On Rails Tutorial by Michael Hartl where we did something similar, but with Twitter followers instead of friend requests. I couldn't wrap my head around it then, and I'm still having trouble now.
Here is the form that I'm using when a user sends a friend request to another user. This is a form partial rendered from #users (hence the user.id)
<%= form_for(current_user.active_relationships.build) do |f| %>
<div><%= hidden_field_tag :friend_id, user.id %></div>
<%= f.submit "Send Friend Request" %>
<% end %>
This passes to my Friendships controller...
def create
#user = User.find(params[:friend_id])
current_user.send_friend_request(#user)
redirect_to current_user
end
Which makes a call to send_friend_reqeust...
def send_friend_request(other_user)
friend_requests << other_user
end
My User model has_many :friend_requests, through: :active_relationships
It works fine, but I started questioning what current_user.active_relationships.build in my form_for helper was even doing. To my (very) untrained eye, it looks like the form is passing a hidden value of friend_id which the Friendships controller then uses to find the User database record associated with that ID.
If all that my form is doing is submitting a hidden User ID, then what is the point of the build method? I know it must do something since removing it breaks my program.
Any help is appreciated. Thank you!
It is an intermediary model between User and FriendRequest models.
By using method BUILD you create a new ActiveRelationship and through that then you can create new FriendRequest.
User >> ActiveRelationship >> FriendRequest
I'm looking for the cleanest way to handle a user permission. It would be used to define if a menu option can be displayed (menu is present in all views) and the access to a page.
So I was wondering which is the cleanest way to do it.
Set an instance variable in each action from the controller validating if the user had access
Add a method in the application helper validating each time it is call if the current user have access
You can define method in your ApplicationController who will check current user permissions. And you can use that method in before_action callback for those actions you need it.
I would recommend to look at cancancan gem (it's community driven support of cancan gem)
Using it it's easy to authorize actions and check abilities to decide show menu item or not.
You can also check out RailsCast about that subject to get understanding of whole idea.
Are you trying to implement an administrator or something similar? I think the cleanest way would be to just make a new column in the users table, which is initialized to false for most, but to true if the user is an admin (or something else). Then you can just make two partials to handle the two cases.
In that case, in your menu view (in your layout or whatnot) you would have this code or something similar:
<% if current_user.admin? %>
<%= render 'admin_page' %>
<% else %>
<%= render 'user_page' %>
<% end %>
Where I assume you define #current_user in your controller, or if you are using Devise, this is handled automatically.
Edit: Yes I endorse the earlier answer, CanCan is a good gem to handle these things also, you should consider using it. In such a case your code would look something like:
<% if can? :update, #user %>
# Edit something
<%= link_to edit_profile_path(#user), class: 'user' do %>
Edit your profile
<% end %>
<% end %>
I'm new to state_machine and am trying to use it to model a job application process.
For a given state, there are possible events that can be triggered by the applicant or by the employer. Is there a way to tag an event to indicate this? For instance, I'd like to be able to get a list of all of the transitions that could be triggered by an employer so when the employer is logged in she can see only the available actions that an employer could take on an application.
Or if there is a better to model this, I'd love to know.
You can use an additional gem like cancan todo some authorisation on this methods.
I had a related problem a few days ago and got this nice answer:
Is it possible to use cancan in a model?
I come up with something like this:
# view
...
<% user.state_transitions.each do |transition| %>
<% if can? "#{transition.event}".to_sym, User %>
<%= link_to transition.event, user_path(user, user: {:state_event => transition.event}), :method => :put%>
<% end %>
<% end %>
...
You have to check this also in the controllers update method.
I have a form where I'd like to create a parent record and a child record at the same time. For a simple example let's say its a Company with the first Employee.
in my controller I do something like:
def new
#company = Company.new
#company.employees.new
end
and in my view this:
<%= form_for(#company) do |form| %>
<div>
<%= form.label :name %>
<%= form.text_field :name %>
</div>
<%= form.fields_for :employees do |employee_form| %>
<div>
<%= employee_form.label :name %>
<%= employee_form.text_field :name %>
</div>
<% end %>
<% end %>
and back in my controller again:
def create
#company = Company.new(params[:company])
#company.employees << Employee.new(params[:company][:employees_attributes]["0"])
# save stuff
end
Question 1:
I couldn't get the employee collection on the company to be populated with the single employee created in the form. When I looked at the params I found the [:employees_attributes]["0"] stuff.
What I have works, but is there a cleaner way to do this?
Question 2:
If the validation doesn't pass for the employee I get a generic "Employees is invalid" instead of the Name required validator message. I get I am calling save on the collection and rails is doing its best to bubble a validation error up, but is there a cleaner way to do this so I can get the errors specific to the employee?
In Short
How can I clean this up so the related models are created automatically from the params, and so that I get the validation messages for a single employee.
Thanks for looking.
1) fields_for arranges for the child objects attributes to be nested inside the parent objects attributes in the params hash that gets sent back to the controller action. To get Rails to automatically update the child objects tell the parent model to accept nested attributes using the accepts_nested_attributes_for declaration.
2) There is an errors object for every ActiveRecord object. Loop through the errors list and display the messages.
Best way to achieve this is to create a partial and a view helper method that will take render the errors for you. then replace the generated errors messages in the forms with a call to your render_error_messages method. You have all the code to do this already in the generated forms. You just need to refactor that code into a partial, create the helper - which should accept an array of model names as a parameter then do what you want with the info. Wither render a partial for each model or render a partial that will deal with child objects as well as the parent object. Totally your call.
3) Change your new action to build rather that create a new child object so instead of
def new
#company = Company.new
#company.employees.new
end
do this
def new
#company = Company.new
#company.employees.build
end
4) Watch those Railscasts to see how accepts_nested_attributes works
http://railscasts.com/episodes/196-nested-model-form-part-1
and
http://railscasts.com/episodes/197-nested-model-form-part-2
Update
So how does the above information leave you in relation to your questions.
1) What I have works, but is there a cleaner way to do this?
You've fixed the new action as per point 3 above right? Now your create action can look like this
def create
#company = Company.new(params[:company])
# save stuff
end
Which is much cleaner as it has reverted to the original generated create action.
You may not think that's much of an update and therefore not that much cleaner. Well in isolation you'd be right. But consider that you could add as many relationships as you like ad add as many fields_for declarations as you like nd you could turn the user -> employee relationship into a has_many (I know that you wouldn't). You could do all that and your create and update actions stay EXACTLY the same and that's why it's cleaner.
2) is there a cleaner way to do this so I can get the errors specific to the employee?
Given my response in point 2 above you know that there is an errors object on the employee object as well as on the user object right? You also know now that you can loop through that errors object to get the messages right?
So you could do this
<% if #user.employee.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.employee.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% #user.employee.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
At the risk of repeating myself I'll just say that you should refactor your error messages view code into a partial that will take any object as a parameter then you can call it from any view thus enabling you to change the styling and the functionality for all your forms.
Hope that's clearer
I recently decided I wanted to list all the users in my Ruby On Rails application - since I couldn't figure out how to list them any other way, I decided to use partials.
I have the following on my administration page (just hooked up to a its own administration controller):
<%= render :partial => User.find(:all) %>
I then have a file called _user.html.erb in my users view folder. This contains the following:
<ul>
<% div_for #user.object_id do %>
<li><%= link_to user.username, user.username %></li>
<% end %>
</ul>
When the application runs and I go to the administration page, I get the following error:
undefined method `id' for 4:Fixnum
It says it's because of this line (which is in the partial file):
<% div_for #user.object_id do %>
I'm unsure why this happens (and have googled for hours to try and find results and only find solutions that don't work for me). I think it's something to do with my usage of the #user instance variable, but I'm not totally sure.
You get that error because div_for expects an active record object as an argument, which it calls the id method on. You pass in a fixnum (the result of #user.object_id), which is not an active record object and does not have an id method.
So pass in #user instead of #user.object_id and it will work.
Also you should use user instead of #user, rails 3 does not set instance variables for partials anymore.
Lose the .object_id part. I seriously can't think why are you using object_id!Do you have a good reason for doing so? Anyway div_for wraps a div around an object, so leave the .object_id part!
instead of object you are using it's column or visa varsa you are using at that time you will get this kind of error.
Example
I am using id instead of user = User.first object.
Try this, it worked for me.
#item.unit_of_measure.name
instead of
#item.unit_of_measure_id.name