Rails nested routes - ruby-on-rails

I am learning Rails and making a reddit clone to help me understand how routing works.
Each post has subreddit. I have the following in my routes file:
resources :subreddits do
resources :posts
end
This way I can create new posts with the following url:
/subreddits/:subreddit_id/posts/new(.:format)
Example:
http://localhost:3000/subreddits/1/posts/new
However I still need to specify in the new posts form what subreddit I want to post to belong to. Wheras what I want is a hidden field that sets the subreddit id to the correct one. The correct one being the one given in the URL.
This is what I currently have:
=simple_form_for #post, html: {multipart: true} do |f|
-if #post.errors.any?
#errors
%h2
=pluralize(#post.errors.count, "error")
prevented this pin from saving
%ul
-#post.errors.full_messages.each do |msg|
%li= msg
.form-group
=f.input :title, input_html: {class: 'form-control'}
.form-group
=f.input :content, input_html: {class: 'form-control'}
=f.hidden_field :subreddit_id, :value => #post.subreddit_id
=f.button :submit, class: "btn btn-primary"
I get the following error:
No route matches {:action=>"show", :controller=>"posts", :id=>33, :subreddit_id=>nil} missing required keys: [:subreddit_id]
I think this is because I am trying to access the subreddit id of a post that hasn't been created yet. How do I solve this? Am I going about it in the wrong direction?

In the new action of the posts_controller, you'll set the #subreddit instance variable
def new
#subreddit = Subreddit.find(params[:subreddit_id])
#post = Post.new
end
In the form, you'll need to change the first line
= simple_form_for [#subreddit, #post], html: {multipart: true} do |f|
:subreddit_id will now be in the url

Try this and check if it works
= f.input :title, :as => :hidden, :input_html => { :value => "some value" }

Related

Change URL by filter

I am using friendly_id so that I can create such URLs:
/search/france/weekly/toyota-95
My routes:
scope to: 'search#show' do
get '/search/:car_country_id/:rental_type_id/:car_group_id', as: 'search_country'
end
At the search#show view I have a form:
<%= form_tag search_country_path, :method => :get do %>
<%= select_tag(:car_country_id, options_from_collection_for_select(CarCountry.all, :slug, proc {|c| c.name }, {:selected => #country}), class: "Select-control u-sizeFull") %>
<%= submit_tag t('shared.search'), class: 'btn btn-primary' %>
<% end %>
And search controller:
#country = CarCountry.friendly.find(params[:car_country_id])
So ok, my intention is to change the URL as:
/search/italy/weekly/toyota-95
But the thing is, Rails params always sending france as car_country_id when I select country from select tag and submit it.
So what should I do?
Currently, two car_country_id are sent to Rails server. You can rename one of them:
<%= select_tag(:new_car_country_id, options_from_collection_for_select(CarCountry.all, :slug, proc {|c| c.name }, {:selected => #country}), class: "Select-control u-sizeFull") %>
In your controller, you should check whether new_car_country_id exists. If it does, then redirect to the corresponding path.
Another way is to make sure that the two car_country_id are the same. You should change the form's submit path once select_tag is updated with JavaScript.

Simple form for params

I have 2 models, blogs and posts
resources :blogs do
resources :posts
end
So, also i have an association. One blog can have a lot of posts. So I put the link to new post in the index of blog:
= link_to 'New Post', new_blog_post_path(#blog)
And then it redirects you to new post, which renders a form like this:
= simple_form_for(#post) do |f|
= f.error_notification
.form-inputs
= f.input :title
= f.input :content
.form-actions
= f.button :submit
And I'm getting an error:
undefined method `posts_path'
I think simple form requires the blog_id but I could't find it. I tried to put #blog.id to simple form, but anyway i got an error (id for nil class)
How can I solve my problem?
I've never used simple_form_for, but it looks to me like your resource has association that is assigned. So you'll need to include it in the form definition:
= simple_form_for([#blog, #post]) do |f|
= f.error_notification
.form-inputs
= f.input :title
= f.input :content
.form-actions
= f.button :submit
And obviously you'll need to have #blog available in your controller action.
Link to the form_for docs:
http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_for
EDIT:
Not sure where posts_path is coming from in your code, but obviously that route doesn't exist as all post paths are dependent on blogs.
Is there anywhere where you reference a post_path in your code?

No route matches [patch] "/happy/node/10003

routes
put '/happy/node/:node_id', to: 'nodes#happy', as: :happy
node controller
def happy
#node = Node.find(params[:node_id])
if #node.update_attributes(:node_status => "happy",
:location_id => params[:location_id],
:hostname => params[:hostname])
redirect_to node_url
end
end
view - form
<%= form_for(#node, url: happy_path(#node), method: :patch, do |f| %>
<%= f.label :location_id, "Location" %>
<%= collection_select :location_id, Location.order(:name), :id, :name, :prompt => "Select Location" %>
<%= f.submit "Save Changes" %>
I am trying to update the node form using a custom action. When i tried this it failed miserably. I will be extremely grateful for your help.
In your routes you are using put, so your method should also be put:
<%= form_for(#node, url: happy_path(#node), method: :put, do |f| %>
You'll need to add a patch route, if you want to continue using PATCH:
patch '/happy/node/:node_id', to: 'nodes#happy', as: :happy

Rails - Silmple Form calls a specified action of my user controller

My problem is that when i try to call a specified method from a simple_form_for form it doesn't work.
Here is my code :
<%= simple_form_for #user, :url => {:action => :register_iban}, :html => { :method => :post } do |f| %>
<div class="col-md-8">
<%= f.input :first_name, :label => t('user-show.payment.form.first_name'), placeholder: "Prénom" %>
<%= f.input :last_name, :label => t('user-show.payment.form.last_name'), placeholder: "Nom" %>
<%= f.input :iban, :label => t('user-show.payment.form.iban'), placeholder: "IBAN" %>
<%= f.input :bic, :label => t('user-show.payment.form.bic'), placeholder: "BIC" %>
</div>
<div class="col-md-8 text-center">
<%= f.submit t('user-show.payment.title'), class: 'btn btn-danger' %>
</div>
<% end %>
So, as you can see, i try to call register_iban method from my user controller.
But when i do that, i have an error : No route matches {:action=>"register_iban", :controller=>"users", :id=>"5", :locale=>nil}
Everytime i create a new method in a controller, i have to create a route in the routes.rb file ? Here, i'd like to make this url : /users/5/register_iban (where "5" is the user id) call my method.
Sorry but i start in ruby and i'm pretty stuck :/
in your config/routes.rb try to add in the users resources
resources users do
member do
post :register_iban
end
end
No route matches {:action=>"register_iban", :controller=>"users", :id=>"5", :locale=>nil}
This error means you're trying to access a route which doesn't exist.
The routes are defined at config/routes.rb:
#config/routes.rb
resources :users do
post :register_iban
end
This will allow you to call the register_iban method in the users controller through your form.
You'll also want to make sure you're calling routes with the appropriate helpers:
<%= simple_form_for #user, url: user_register_iban(#user) %>

redirect from new action to create action with params

Im trying to design a shopping cart. i.e a customer shopping online adds a product to their trolley.
I want to go straight to create action from my new action without going to new.html.erb with pre-set values in my params
Here is what I have so far:
#trolley_id += 1
redirect_to :controller => 'trolleys', :action => 'create', :id => #trolley_id, :something => 'else', method: :post
This redirects me to my index action
To do this with javascript templates, it would look like this:
view
= form_form Trolley.new, remote: true do
-# form goes here
The remote true will submit it as javascript, which will try to render a javascript template.
Your create action can either render :create or let Rails render your template automatically. Since it came in as a javascript request, Rails will render the template with format js.
trolleys/create.js.erb
var html = "<%= j render 'trolley_row', trolley: #trolley %>
$('table.trolleys body').append(html);
I managed to resolve my problem. I created a form in my Product_controller#show that will go straight to my Trolley_controller#create and create an entry in my Trolleys table
<%= simple_form_for [#product, #trolley] do |f| %>
<%= f.input :quantity, collection: 1..12, prompt: "select quantity" %>
<%= f.input :product_id, :as => :hidden %>
<%= f.input :user_id, :as => :hidden %>
<%= f.button :submit, "Add to Basket" %>
<% end %>

Resources