Rails how to get customer name in orders view? - ruby-on-rails

Trying to learn rails, building very simple app.
by going to
<%= link_to 'Show Orders', orders_path %>)
I get list of orders for one customer. There are some attributes stored for customer, including first name and second name.
I try to create header with text "Listing orders for John":
<h1>Listing Orders for <%= #customer.try(:name) %></h1>
Result is:
Listing Orders for
What do i do wrong?
UPD:
Well, customer and order actually "nicknames" for Feature and Assets (relations are the same), for easier understanding. Sorry for confusing.
So, Assets controller show method:
class AssetsController < ApplicationController
before_action :set_asset, only: [:show, :edit, :update, :destroy]
def show
end
private
def set_asset
#asset = Asset.find(params[:id])
end
Feature model:
class Feature < ActiveRecord::Base
has_many :assets, dependent: :destroy
end
Asset model:
class Asset < ActiveRecord::Base
belongs_to :feature
end

try returns nil instead of raising exception.So that customer.name is nil.I am sure it wont be coming for all customers.remove try and code will raise exception as name is nil

Ok, finally managed it. A bit different approach - i now show assets on features pages.
class FeaturesController < ApplicationControll
def show
#assets = Asset.where(feature_id: #feature.id)
end
And in features/show.html.erb
<h2>Assets</h2>
<%= render #feature.assets %>
Seems like total magic to me, but still works just like needed.
This is closed now.

Related

What is the Rails way of handling edits made to a resource's ActiveStorage attachment(s)?

I'm trying out ActiveStorage for the first time and wondering what the convention is for controller code used to purge some or all of a resource's attached files?
Two solutions I can see, and hate:
A designated controller just for managing attachments (which would omit any kind of resource specific callbacks)
In each resource controller add some kind of logic to the destroy methods
What is the Rails way of handling edits made to a resource's ActiveStorage attachment(s)?
I’d choose the first solution you considered:
A designated controller just for managing attachments (which would omit any kind of resource specific callbacks
This is roughly what we do in Basecamp. Here’s a demo:
# app/models/event.rb
class Event < ApplicationRecord
belongs_to :user
has_many_attached :highlights
end
# app/controllers/events/highlights_controller.rb
class Events::HighlightsController < ApplicationController
before_action :set_event, :set_highlight
def destroy
#highlight.purge_later
redirect_to #event
end
private
def set_event
#event = Current.user.events.find(params[:event_id])
end
def set_highlight
#highlight = #event.highlights.find(params[:id])
end
end
# config/routes.rb
Rails.application.routes.draw do
resources :events do
resources :highlights, controller: "events/highlights"
end
end
<%# app/views/events/show.html.erb %>
<% #event.highlights.each do |highlight| %>
<%= link_to image_tag(highlight.representation(resize: "200x200>")), highlight %><br>
<%= link_to "Delete this highlight", event_highlight_path(#event, highlight), method: :delete %>
<% end %>

ActiveRecord query in views and helpers in Rails

I have the following associations defined in my application:
class Person
belongs_to :type
end
class Type
has_many :people
end
Now, in the new and edit form for person, I need to give a dropdown that will show all the types which will come from the Type model.
Now there are two approach to do the same:
1. make an instance variable in controller for types and access that in the form view.
class PeopleController
before_action :get_types, only: [:new, :create, :edit, :update]
def new
end
def create
end
def edit
end
def update
end
private
def get_types
#types = Type.all
end
end
person/_form.html.erb
...
<%= f.select :type_id, #types.collect{ |type| [type.name, type.id]} %>
...
2. Making a database query in the person_helper
person_helper.rb
module PersonHelper
def get_types
Type.all
end
end
person/_form.html.erb
...
<%= f.select :type_id, get_types.collect{ |type| [type.name, type.id]} %>
...
So, I want to know which is the better approach and why.
Note: As per MVC paradigm, controller will provide the necessary data to the views. Neither I am not able to find any difference in the query execution in both the cases nor, I am able to find any good explanation regarding the same apart from the MVC part.
The idea with the helper is reuse functionalities for example formatting something or extract complicated logic.
So, if that query is something that you will need in many cases, would be a good idea have it in the helper, there is not really an difference in the query execution, is more about use and have a code more clean.

Rails Form Associations - Passing id From Previous Page

Trying to figure our how to set up associations in form.
I have 3 models:
class Request < ActiveRecord::Base
has many :answers
has many :users, through: :answers
end
class Answer < ActiveRecord::Base
belongs to :user
belongs to :request
end
class User < ActiveRecord::Base
has many :answers
has many :requests, through: :answers
end
I am trying to figure out: how to have a User link to Answer#new from Request#Show, and then create an Answer record passing in the Request#Show request_id from the previous page - creating an association between the User's Answer and the Request he was viewing.
My method of doing this now is: I flash the request_id value on Request#Show, and then when a User links to Answer#new, it passes the flashed value into a hidden form tag on Answer#new. This does not seem like the best way to do this.
Any thoughts?
Kudos for the creative approach using flash, however your right there is an easy way. You can pass parameters much between controllers just like passing parameters between methods using the route names.
I didn't quite follow what it was you were trying to achieve in this case but it looks like this blog entry here should get you started..
https://agilewarrior.wordpress.com/2013/08/31/how-to-pass-parameters-as-part-of-the-url-in-rails/
Good luck!
User link to Answer#new from Request#Show
This can be achieved with either sessions or nested resources (or both!). Let me explain:
I would definitely add a nested resource to your requests routes:
#config/routes.rb
resources :requests do
resources :answers, only: [:new, :create] #-> url.com/requests/:request_id/answers [POST]
end
This gives you the ability to call a "nested" route (IE one which sends data to a child controller, and requires "parent" data to be appended to the request).
In your case, you want to create an answer for a request. The most efficient way is to use a routing structure as above; this will allow you to use the following controller method:
#app/controllers/answers_controller.rb
class AnswersController < ApplicationController
def new
#request = Request.find params[:request_id]
#answer = #request.answers.new
end
def create
#request = Request.find params[:request_id]
#answer = #request.answers.new answer_params
#answer.save
end
private
def answer_params
params.require(:answer).permit(:title, :body)
end
end
The above gives you the ability to create an answer by passing the request_id to the nested route. You must note the corresponding route will require a POST method in order to work.
You don't need the new method. If you wanted it, it can easily be handled with the above structure.
Passing the user is a little more tricky.
You can either use the routes, or set a session.
I would personally set a session (it's cleaner):
#app/controllers/requests_controller.rb
class RequestsController < ApplicationController
def show
session[:user_id] = #user.id #-> I don't know how you populate #user
end
end
This will give you the ability to access this session here:
#app/controllers/answers_controller.rb
class AnswersController < ApplicationController
def new
user = User.find session[:user_id]
end
end
#app/views/requests/show.html.erb
<%= link_to "New Answer", request_new_answer_path(request) %>
--
If you're using Devise, the user object should be available in the current_user object (which means you don't have to set session[:user_id]):
#app/controllers/answers_controller.rb
class AnswersController < ApplicationController
def new
## current_user available here if using devise
end
end
To assign a #user to the new answer record, just do this in answers#create:
#app/controllers/answers_controller.rb
class AnswersController < ApplicationController
...
def create
#request = Request.find params[:request_id]
#answer = #request.answers.new answer_params
#answer.user = current_user
#answer.save
end
end
Something like this worked for me:
I have two models (Formula and FormulaMaterial)
Formula has_many FormulaMaterials, which belongs to Formula
My Formula controller sets #formula like so:
#formula = Formula.find(params[:id])
I list my Formula Materials in my Formula show.html.erb by declaring it in my Formula controller like so:
#formula_materials = FormulaMaterial.where(:formula_id => #formula)
When I want to add a new FormulaMaterial to my Formula, the "New Formula Material" button in my show.html.erb file looks like this:
<%= link_to 'Add Material To Formula', new_formula_material_path(:formula_id => #formula), class: "btn btn-success" %>
In the "new_..._path" I set the associated id to the #formula variable. When it passes through to the new.html.erb for my FormulaMaterial, my URL looks like so:
http://localhost:3000/formula_materials/new?formula_id=2
In my FormulaMaterial new.html.erb file, I created a hidden_field that sets the value of the association by using "params" to access the formula_id in the URL like so:
params[:formula_id] %>
I am not sure if this is the best way to do this, but this way has allowed me to pass through the view id from the previous page as a hidden, associated and set field in the form every time.
Hope this helps!

Ruby on Rails: Finding Records using passed parameters

I'm making an online magazine style website and am having difficulties getting the syntax right for my final part of the project. The relationships are working as they should I am just having trouble calling the intended records.
Each post belongs to a category with category_id being the foreign key. When a user clicks this link, <%= link_to 'News', categories_path(:category_id => 1) %>, I'd like for them to be brought to an index page showing only posts with a category_id matching the parameter in the URL.
I've been messing around in the categories_controller.rb for almost two hours now with no luck. Anyone be so kind as to throw this noob a bone?
There are a few components of what you're trying to do. We'll start with the routing side, and make our way to the controller.
First, you need to make the proper routes. Since the post belongs to a category, you will need to have the category id in order to handle performing any sort of operations on the posts. So we'd need a route like /category/:category_id/posts/:id. Luckily, Rails has something to handle this. If you nest a resources within a resources, it'll generate these routes. So, we end up with this:
resources :categories do
resources :posts
end
And that will get you what you want in terms of routes. But now we have to actually implement it. So, we're going to need to take a look at the controllers. If you notice, all of those routes have a :category_id - so looking up the category shouldn't be too difficult:
class PostsController < ApplicationController
before_action :load_category
private
def load_category
#category = Category.find(params[:category_id])
end
end
Now, you have the category loaded, and it shouldn't be too difficult to implement the other methods from there:
class PostsController < ApplicationController
before_action :load_category
def index
#posts = #category.posts
end
def show
#post = #category.posts.find(id: params[:id])
end
# ...
end
In order to reference the Post index path, you'll have to use category_posts_path helper.
Your problem is that you're trying to use an existing route to handle some new functionality (for which it was incidentally not designed). That categories_path route is meant to take you to your category index.
You need to create a method in your controller to perform the functionality you want to see.
class PostsController < ApplicationController
...
def posts_by_category
#posts_by_category = Post.where("category_id = ?", params[:category_id])
end
...
end
Then you're going to need a view to display your #posts_by_category array (I'll leave this exercise to you).
And now for the key to your problem: you need a route pointing to the posts_by_category method.
get 'posts/posts_by_category' => 'posts#posts_by_category'
Now you should be able to create your link with the correct route:
<%= link_to 'News', posts_by_category_path(:category_id => 1) %>

Link to random page where content present

I am using Rails 4.
I have two resources: articles and subarticles. subarticles are nested into articles.
I currently have a random button which takes the user to a random article. However, I would like it to only take them to an article page in which the subarticle is present.
What is the best way to go about this? I'm having trouble finding documentation.
Here is my random method in the articles_controller:
#items = Article.all
#randitem = #items[rand(#items.count)]
and in the view:
<%= link_to "Random Page", article_path(#randitem) %>
Did you setup a counter_cache? If not, I would recommend you to do so as it will allow you to do what you want in a more elegant way (with less code and less database query as well) : http://guides.rubyonrails.org/association_basics.html
class Article < ActiveRecord::Base
# The article table needs then to have a `subarticles_count` field
has_many :subarticles
end
class Subarticle < ActiveRecord::Base
belongs_to :article, counter_cache: true
end
Then in your controller, you can query the articles that have subarticles :
class ArticlesController < ApplicationController
def index
#items = Article.includes(:subarticles).where('subarticles_count > 0')
#randitem = #items[rand(#items.count)]
end
end
By the way, it's cleaner to use the Ruby sample method to get a random item from a collection :
class ArticlesController < ApplicationController
def index
#items = Article.includes(:subarticles).where('subarticles_count > 0')
#randitem = #items.sample
end
end

Resources