Nested Ressources in Ruby on Rails - ruby-on-rails

It's actually supposed to be very trivial, but I'm experiencing strange issues.
I'm developing a Game Database, where Users can chart Game Entries and also write reviews to those reviews. Of course a Reviews URL (the show view) must be dependent of the game's id, like localhost:3000/games/1/reviews/2
So these are my routes
resources :games do
resources :reviews
end
And I want to open the show-view of a review with
<%= link_to "zum Review", game_review_path(#game, #review) %>
this is all basic tutorial stuff.
But I only recieve a Routing error. Trying instead this approach
url_for([#game, #review])
At least won't result in a routing error, but Not the reviews show-view is opened, but the game's show view, which is where this link is actually placed!
My models associations are set corretly and my controllers actions are all basic tutorial stuff. What am I doing wrong?

In your erb file try passing the local variable in the left argument and the name of the nested model in the field to the right. If you use 2 local variables you will get a routing error. #game is the local variable and review is nested under games so the below code should fix your issue.
Try:
<%= link_to "zum Review", game_review_path(#game, review) %>

Related

How do rails forms work without a model?

I am trying to challenge my learning by creating a simple project using rails forms, however I have gotten really stuck and can't find any information that seems to help online.
What I am trying to do:
I want to create a rails application with no model (so no persistence of data). Simply put I want a user to enter a Soundcloud URL which then gets transferred to the controller where I can do more logic. Essentially I am really trying to understand the connection between the Rails form and the controller in rails. I have spent all day reading about HTML forms, as well as googling this exact question without really fully getting it.
I understand there are different form helpers, but what I cannot seem to understand is how to use these without a model. My biggest hang up right now is I cannot get the form values transferred to the controller. I thought I understood RESTful routes, PUT/GET etc.. but this has made me super frustrated that I cannot seem to get my head around this. Any advice is super appreciated.
The code:
Below is the specific code I am struggling with, currently when I get submit the form it crashes giving me an error based on routes, and that's where I am stuck.
Problem code is found in the _form.html.erb file in views:
<%= form_tag '/show' do %>
<%= label_tag(:soundcloud_url, "Please enter a valid Soundcloud Artist URL:") %>
<%= text_field_tag(:soundcloud_url) %>
<%= submit_tag("Let's go!") %>
<% end %>
Routes.rb:
Rails.application.routes.draw do
resources :soundcloud_query
root 'soundcloud_query#index'
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
Error:
Routing Error
No route matches [POST] "/show"
rake routes output:
Prefix Verb URI Pattern Controller#Action
soundcloud_query_index GET /soundcloud_query(.:format) soundcloud_query#index
POST /soundcloud_query(.:format) soundcloud_query#create
new_soundcloud_query GET /soundcloud_query/new(.:format) soundcloud_query#new
edit_soundcloud_query GET /soundcloud_query/:id/edit(.:format) soundcloud_query#edit
soundcloud_query GET /soundcloud_query/:id(.:format) soundcloud_query#show
PATCH /soundcloud_query/:id(.:format) soundcloud_query#update
PUT /soundcloud_query/:id(.:format) soundcloud_query#update
DELETE /soundcloud_query/:id(.:format) soundcloud_query#destroy
root GET / soundcloud_query#index
Github link:
https://github.com/gaelant/simple_soundcloud_app/commit/09c4c4df524bb721a0f472b4378cd8c1ff18177f
Note: I understand this is a basic question but I have just gotten really confused with this. I know the way the code above is written is not correct, but I have tried so many different things and I just don't understand what is going on, or if this is even possible without a model.
Your /show form action points to nowhere. rails routes shows you which url is valid and to which controller#action each of them lead.
The correct form action would be
<%= form_tag '/soundcloud_query' do %>
<%= label_tag(:soundcloud_url, "Please enter a valid Soundcloud Artist URL:") %>
<%= text_field_tag(:soundcloud_url) %>
<%= submit_tag("Let's go!") %>
<% end %>
A far more better way is to use the url_helpers available through your defined ressource in Routes.rb
Doing so your form action would look like this
<%= form_tag soundcloud_query_index_path do %>
<%= label_tag(:soundcloud_url, "Please enter a valid Soundcloud Artist URL:") %>
<%= text_field_tag(:soundcloud_url) %>
<%= submit_tag("Let's go!") %>
<% end %>
The hardcoded and the url_helper based solution will route your request to a controller class named SoundcloudQuery where the action create will be called. Inside this action you have to put all needed logic.
It's also possible do define that /show should point to a specifc controller and action. This would look like this.
post '/show', to: 'mycontroller#myaction', as: 'mypathnameforhelper'
A much more better explanation with many examples about routes and how to use them can be found in this quite good guide.
Rails Routing from the Outside In
Hint: You should stay close to the ROR naming conventions. Controllers should have pluralized names. So you should define your routes like this:
Rails.application.routes.draw do
ressources :soundcloud_queries
root 'soundcloud_queries#index'
end
and then rename your controller class and file accordingly into SoundcloudQueries and soundcloud_queries.rb. But this is not mandatory.
I think in this case you should not use the url in the form_tag but the controller action.
Let's say you've got a view called my_form.html.erb and a submit_form method in your soundcloud_controller.rb
def submit_form
params[:soundcloud_url] your logic
end
I'd set up the routes like this:
get 'soundcloud_query' => 'soundcloud_query#my_form' // didn't want to use 'resources' but it doesn't matter
post 'soundcloud_query' => 'soundcloud_query#submit_form'
The form would then look like:
<%= form_for :this_doesnt_matter, action: :submit_form do |f| %>
<%= f.text_field :soundcloud_url %>
<%= f.submit %>
<% end %>

How to define a link path

I'm trying to figure out how to make an app with Rails 4. I keep getting stuck on basic things and I don't seem to be able to identify principles to use going forward.
I have a profile model and a industry model. The associations are:
Profile:
has_and_belongs_to_many :industries, join_table: 'industries_profiles'
Industry:
has_and_belongs_to_many :profiles, join_table: 'industries_profiles'
In my profile show page, I'm now trying to link to the industry page:
<% #profile.industries.limit(5).each do |industry| %>
<%= link_to industry.sector.upcase, industry_path(#industry) %>
<% end %>
I can't find anything that works for this link.
I have tried the following:
industry_path(#profile.industry)
industry_path(#profile.industry_id)
industry_path(industry)
industry_path(profile.industry)
industry_path(industry.id)
industry_path(industry_id)
But all of them are guesses. I don't know how to ready the API dock so I can't understand any of its content.
Can anyone see how to link to a show page of the other side of the HABTM association for a single record?
You can grab a list of your routes by running rake routes | grep industry in your command line, which will give you a table with the prefix, action, and uri pattern. For example:
industries GET /industries(.:format) industries#index
POST /industries(.:format) industries#create
new_industry GET /industries/new(.:format) industries#new
edit_industry GET /industries/:id/edit(.:format) industries#edit
industry GET /industries/:id(.:format) industries#show
PATCH /industries/:id(.:format) industries#update
PUT /industries/:id(.:format) industries#update
DELETE /industries/:id(.:format) industries#destroy
In your case, you should look at the show path. Which is industry and you append _path to the end of whatever your prefix is above, which comes out to be industry_path. And since you have declared your variable industry when defining your loop, you can use that instead of the instance variable.
Short answer: industry_path(industry)

undefined method `pushes_path' for #<#<Class:0x007f85a15c6c90>

i'v been trying to resolve this error for the past 5 hours and I'm gonna burn my computer if I can't solve this.
undefined method `pushes_path' for #<#:0x007f859d605250> this is the error code I'm getting but i don't understand why.
this is my index.html.erb file inside of the interaction
<%= simple_form_for #push do |f| %>
<%= f.input :payload, as: :text %>
<%= f.input :segment, as: :radio_buttons %>
<%= submit_tag "start the campaign" %>
<% end %>
and this is my interaction controller
class InteractionController < ApplicationController
def index
#push =Push.new
end
end
Push is my table in the database and i'll get the inputs and write them in the database to use them for later one.
and this is my routes file
devise_for :partners
get 'home/index'
get 'segmentation/index'
get 'interaction/index'
root to: "home#index"
i really don't know why its looking for pushes_path, what am i doing wrong?
form_for
The problem you have is that your form_for method is going to try and generate a route based off your #path object. And as such, if you don't have a path created for it, you'll receive the error you're getting:
:url- The URL the form is to be submitted to. This may be represented
in the same way as values passed to url_for or link_to. So for example
you may use a named route directly. When the model is represented by a
string or symbol, as in the example above, if the :url option is not
specified, by default the form will be sent back to the current url
(We will describe below an alternative resource-oriented usage of
form_for in which the URL does not need to be specified explicitly).
The bottom line is that as Rails is object orientated, its built around the assumption that you'll have routes set up to handle the creation of individual objects.
Every time you use form_for, Rails will attempt to construct your routes from your object -- so if you're trying to do the following, it will treat the routes as photo_path etc:
#app/views/pushes/new.html.erb
<%= form_for #push do |f| %>
...
<% end %>
--
Fixes
As #mandeep suggested, there are several fixes you can employ to get this to work:
Firstly, you can just create a route for your push objects:
#config/routes.rb
resources :pushes
Secondly, as you're using a different controller, you'll want to do the following:
#config/routes.rb
resources :interactions
#app/views/pushes/new.html.erb
<%= form_for #push, url: interaction_path do |f| %>
...
<% end %>
This will route your form submission to the interactions controller, rather than the pushes controller that you'll get by default!
Objects
Something to consider when creating Rails-based backends is the object-orientated nature of the framework.
By virtue of being built on Ruby, Rails is centered on objects - a term for a variable, which basically encompasses much more than just a piece of data. Objects, in the case of Rails, are designed to give the application:
Once you understand this, the entire spectrum of Rails functionality becomes apparent. The trick is to realize that everything you do in Rails should be tied to an object. This goes for the controllers too:
--
Ever wondered why you call resources directive in your routes, for a controller? It's because you're creating a set of resourceful routes based for it:
Do you see how it's all object orientated?
This gives you the ability to define the routes for specific controllers etc. The most important thing to note is how this will give you the ability to determine which routes / controller actions your requests should go
--
There's nothing wrong in using the controller setup as you have - the most important thing is to ensure you're able to define the custom URL argument, as to accommodate the non-object based structure
In your index action you have
def index
#push =Push.new
end
and your form has
<%= simple_form_for #push do |f| %>
so your form is looking for /pushes with post verb or pushes_path and you don't have that route in your routes.rb file so to fix this you need to add this in routes.rb:
resources :pushes
Update:
when you add resources :push rails basically creates seven different routes for you. One of which is
POST /pushes pushes#create create a new push
and if you look at the html generated by your form it would be something like:
<form action="/pushes" class="new_push" id="new_push" method="post">
// your fields
</form>
notice the action and verb so when you submit your form your routes are checked for them and since you didn't define them in your routes you were getting this error
And how will i be able to use the params i m getting from this form with this new resource addition?
Your form will take you to pushes_controller create action so first of all you'll have to define them. You can access them simply by params[:pushes] in your controller action but since you want to create a new record so you'll have to permit those attributes, checkout strong parameters
If you are using rails >= 4 then you can do
class PushesController < ApplicationController
def create
#push =Push.new(push_params)
if #push.save
redirect_to #push
else
render 'interaction/index'
end
end
private
def push_params
params.require(:push).permit(:attributes)
end
end
If you are using rails < 4 then instead of permitting these attributes(because strong parameters feature came from rails 4) you'll have to tell rails that these attributes are accessible by writing this in your pushes.rb
attr_accessible :attribute_name
Why it is assuming that its pushes controller?Because of the Push.new creation?
That's because if you look at your index action #push = Push.new so #push contains a push object with nil values(as you have just initialized it) so this is where rails magic comes, rails automatically tries to figure out url of your form and since your #push is only an initialized variable so rails takes you to create action for it. For details you should checkout rails polymorphic urls If you want your form to go to interaction_controller or some other url then you'll have to specify the url option for it
<%= form_for #push, url: "your_url_for_custom_method" %>
// other fields
<% end %>
And in the end you should really read docs

Couldn't find Movie without an ID

App has 2 simple models and I use TMDb api. Movie & MovieReviews. When I try to to visit this URL
localhost:3000/movies/%23<Tmdb::Movie:0x007ff0608f4398>/movie_reviews/new
where I should see the form for submitting reviews, I get the error. Also, the url seems kinda bad. How can I get the movie id? It also shows
parameters:
{"movie_id"=>"#<Tmdb::Movie:0x007ff0608f4398>"}
and this is MovieReviewsController#new
def new
#movie = Movie.find(params[:id])
#movie_review = #movie.movie_reviews.new
end
Source code
Please replace
<%= link_to "Review it!", new_movie_movie_review_path(#movie) %>
By
<%= link_to "Review it!", new_movie_movie_review_path(#movie.id) %>
Problem is you do not reference movie id but movie object. This is why you have your strange URL parameter.
Once changed, you will have to adapt your MovieReviewsController.
But please be careful, I see you are trying to use "movie review". When I look at link you provided about Tmdb API, I can read " Missing Resources: Review ".
I think you have several issues:
localhost:3000/movies/%23<Tmdb::Movie:0x007ff0608f4398>/movie_reviews/new this will never work. Tmdb::Movie:0x007ff0608f4398 is the internal object id of the class instance. The url should look like localhost:3000/movies/1/movie_reviews/new. This will allow you to add a new review to the movie with id: 1
In your config/routes.rb file you have declared several urls explicitly and added the root route above other resources. The root route should always be the last declared route. Also get "movies/show" and get "movies/index" routes are already handled by resources :movies so you can remove those.
Routes file should look like this:
SampleMovies::Application.routes.draw do
resources :movie_reviews
resources :movies do
resources :movie_reviews
end
root 'movies#index'
end
To see all avalaible routes for your application. Go to the project directory and type: rake routes It will show all available urls included required and optional parameters.
PS looking at the rest of your code, I strongly advice you to have a look at: http://guides.rubyonrails.org/getting_started.html its a most excellent tutorial on the basics of rails.

How do I take this from the console to a controller and view

I'm learning Ruby on Rails (my first MVC) and have successfully setup a many-to-many relationship between "Agents" and "Zipcodes." What I'm trying to do currently is to get the associated agent based on the zip code entered by the user. I'm able to so successfully in the console, but am having a difficult time translating it to a controller and view.
What I do in the console:
zip = Zipcode.find_by_zip(gets.chomp)
=> 92562
zip.agents
The hangup I'm having is how to translate this into an action that I can access from a view with a form.
I've started by defining the action (agents#find), but am stumped as to whether this is correct and what comes after it.
def find
#user_zip = Zipcode.find_by_zip(params[:zip])
end
Hopefully someone awesome in here can point a n00b in the right direction.
When just starting with rails, I'd suggest avoiding custom actions like #find as much as possible, and instead sticking to the "Big 7" RESTful routes. Rails is really smooth when you work with it and do what it expects.
It sounds like maybe you're trying to identify a given zipcode, and then list all the agents associated with it. That sounds like a #show on Zipcode.
config/routes.rb
resources :zipcodes
app/controllers/zipcodes_controller.rb
ZipcodesController < ApplicationController
def show
#zipcode = Zipcode.find_by_zip(params[:id])
end
end
app/views/zipcodes/show.html.erb
<div>
<p>This zipcode has the following agents:</p>
<ul>
<%= #zipcode.agents.each do |agent| %>
<li>Agent #<%= agent.id %></li>
<% end %>
</ul>
</div>
You can see this page by browsing to /zipcodes/[zip].
Just put #user_zip = Zipcode.find_by_zip(params[:zip]) in the controller instead of the model.
In the view you will be able to call #user_zip.
Welcome to Rails! I recently started learning Rails as well, but I think I can help: A controller action will redirect by default to a view with the same name. So after assigning the value of #user_zip, the controller will serve up agents/find.html.erb, which will have access to #user_zip. Since #user_zip is an instance of Zipcode, you'd be able to use #user_zip.agents.
Somewhat tangential, but I also suggest considering using search rather than find for the action name, only because find and its variations are used elsewhere in Rails.

Resources