avoid issue in the mvc - ruby-on-rails

I know that a view shouldn't have any knowledge, of the model or the controller but i am not to sure how to avoid it.
The issue is i am trying to fetch the information from the controller or the model before i need to manipulate it in my view.
Here the code
Model
USER LOCATION ARTICLE
id user_id title
first article_id ...
last
...
Relationship
user has many locations
article has many locations
location belongs to user
location belongs to article
controller
#userlocation = #user.locations
View
<% #userlocation.each do |event| %>
...
<% evTitle = Article.find_by_id(event.article_id) %>
<%= evTitle.title %>
<% end %>
Obviously its not the best not sure how to do the query in the controller, and evTitle doesnt report properly why?

In controller you can do like this:
#userlocations = #user.locations
#locations_articles = Article.find_all_by_id(#userlocations.map(&:article_id).uniq)
Then you can use #locations_articles in view. Avoid using db queries in view.
<% #locations_articles.each do |article| %>
<%= article.title %>
<% end %>

You can first watch the rails cast multiple form episode at here :-
http://railscasts.com/episodes/196-nested-model-form-part-1
and there is an attribute that first you should define in model to access the information at single view form.
def new
#survey = Survey.new
3.times do
question = #survey.questions.build
4.times { question.answers.build }
end
end

Related

How to show a view based on user attribute?

In my Rails app, I have a store with products and users. Both of those have models and controllers.
What I want to achieve is to show on a view template a product to a current_user based on the attribute from a model that he has. For an example if a user has "Female" attribute from user model, and then to show some products related to this attribute. How can I achieve this?
These are my product views where all products are showed:
<% #products.each do |product| %>
<%= render "product_row", product: product, order_item: #order_item %>
<% end %>
_product_row.html.erb
<h4><%= product.name %></small></h4>
<div class="image">
<%= image_tag product.image.url(:original), class: "img-responsive" %></div>
<p>Some description.</p>
Add to Package
It sounds like you need to retrieve objects from your product class based on an attribute from the User class. Sounds like a basic service object or just a method on the user:
class User < ActiveRecord::Base
def products_for_gender
if gender == 'female'
Product.where("do some logic here based on female")
elsif gender == 'male'
Product.where("do some logic here based on male")
else
#do some other logic just in case it's nil
end
end
end
then in your controller you do this
#products = current_user.products_for_gender
in your view you then render a list with those products. This prevents you from putting logic in your view, which is rarely a good idea.
Also there's more abstraction possible, the if statement is not the prettiest, but this will cover your issue i believe. Eventually you could look into using service objects for example, https://blog.engineyard.com/2014/keeping-your-rails-controllers-dry-with-services
How are you saving the users model. If you are using devise then you have current_user helper method available in your views and you can use that to get the curren_user.gender attribute and show the view based on this

How to query two tables from database in one controller

I have two tables which are one to many (1 challenge to many entry)
I want to get the last entry for all challenges but I also want to get the title of the challenge for that last entry.
So far I have:
def index
#discovers = Challenge.all.map{|c| c.entries.last}
end
How to I also add the fact I want the Challenge.title?
def index
#challenges = Challenge.all
end
Then inside your view
<% #challenges.each do |challenge| %>
<%= challenge.title %> # will give you challenge title
<%= challenge.entries.last %> # will give you last entry for the challnge
<% end %>

How do you recurse if statements

Im trying to make a category system with parents. Here is how my database is structured.
- id
- name
- parent_id
Basically what I want it to do is check if there is a parent id, and if so then check if the parent id, and if that parent has a parent id, and so on. Then output the parents in order until it reached the child.
Currently what I am doing (in Ruby/Ruby on Rails) is this:
<% #cat = Category.find_by_id(#project.category) %>
<% if #cat.parent_id.nil? %>
<%= #cat %>
<% else %>
<%= Category.find_by_id(#cat.parent_id).name%> => <%= #cat.name %>
<% end %>
The problem with this is that it only gets one parent. I need it to recurse and constantly gather the parent until it hits and end, and also I dont want it to take up too much memory. Any help would be appreciated. Thanks! :)
Add a method on your model to search for the parent
class Category
# inline, less memory usage
def last_parent
last = self
while last.parent
last = last.parent
end
last
end
# recursive, better readability
def last_parent_recursive
if parent
parent.last_parent_recursive
else
self
end
end
end
then, on your view:
<%= #cat.last_parent %>

dynamic fields in the rails view

I want to show fields from the database dynamically.i.e, if suppose
in one case my #user object reads from users table
#user = User.new
in another case #user object reads from posts table
#user = Post.new
Then dynamically my view(new page) shows the fields based on the model selected.
<% for column in #object.class.column_names %>
<%= #object.send(column) %>
<% end %>
EDITED (To exclude some columns from the view)
exclude_columns = ['id', 'created_at', 'updated_at']
<% for column in #object.class.column_names
next if exclude_columns.include?(column) %>
<%= #object.send(column) %>
<% end %>
This might be more than you are asking for, but perhaps you want to have a look at the presenter pattern. This will let your view make use of one single interface while hiding away the view logic.
I think this post will give you a nice introduction to the topic: http://mikepackdev.com/blog_posts/31-exhibit-vs-presenter
I'm going to disagree with Salil. you should never do assigns in the view (ERB). If you're doing that, you need to move towards a helper or a presenter depending.
Why would you not just walk the tree? #users should, by name, return a collection of users. #user.posts would walk the relationship tree. I'm curious why you're fighting the rails default way of working. Can you share more code to help us understand?

Complex form with Rails

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

Resources