Rails Route Issue - Plural or Singular? - ruby-on-rails

I'm unsure what to post here script wise. I'm trying to complete a tutorial and it wants me to create Advertisement. I made the Controller/Model, but I'm having a couple issues.
My index is showing all of the ads, but when I try to create one, I get an error
undefined method `advertisements_path' for #<#:0x007fa84c5a59f0>
Now I see it mentions 'advertisementS' so I know it wants plural. My controller is singular. If I go into routes and I add
resources :advertisements AS WELL, it -will- allow me to create an Ad, but when it goes to submit it, I get errors (Likely since everything is still set to AdvertisementController (Singular).
I'm not quite sure what code to post, so I'll post things I think are relevant.
Rails.application.routes.draw do
resources :posts
resources :advertisement
This is where I can add a plural resources to get it to 'load' but fail to save.
<%= form_for #advertisement do |f| %>
<div class="form-group">
<%= f.label :title %>
<%= f.text_field :title, class: 'form-control', placeholder: "Enter post title" %>
<div class="form-group">
<%= f.submit "Save", class: 'btn btn-success' %>
</div>
THIS is where I am getting my initial warning, on the "form_for #advertisement" line.
def create
#advertisement = Advertisement.new
#advertisement.title = params[:advertisement][:title]
#advertisement.copy = params[:advertisement][:copy]
#advertisement.price = params[:advertisement][:price]
if #advertisement.save
flash[:notice] = "The Ad was saved."
redirect_to #advertisement
else
flash[:error] = "There was an error saving the ad. Please try again."
render :new
end
end
This references my def create from AdvertisementController.
(Essentially the purpose of the tutorial is to duplicate almost exactly what we do for Posts. It worked, up until now. Functionality works until I go to create a new one.
I've been working on it for a couple hours, but I'm struggling to understand when to use plural vs singular.
(There is no integration as of yet, so belong_to isn't relevant yet.

The rails convention of naming Controllers is plural. It's possible to use singular, but it gets you into problems like you are having now. So, rename your Controller to plural version and it should be fine.
Also
resources :posts
resources :advertisement
is not consistent, i would suggest that you keep your route names plural as well.

map.resources :dogs # => blows up map.resources :dog # is ok, but... dogs_path # => blows up dog_path # => ok
Based upon input I found in another thread, this made me realize I would need a plural controller.
Re-creating the controller as plural (advertisementS) resolved issue.

Related

How do I get a table controller to display a foreign key association? [Rubymine 2020.2.3, Ruby.2.7.2p137, gem 3.1.2]

I am near the deadline on a college project (3 weeks) and I have had encountered several issues. It being a project course, I can't always refer to my tutor.
Earlier I have asked a question that has provided solutions for a table that did not have a foreign key, thanks to the kind people on this site, it is finally resolved. A more long-standing issue is getting table to work with a foreign key, one of these tables would never display a single data record at the index.
This is the Create method of the 'Shipment' table controller where I try to create an association to the 'Courier' to which the Shipment belongs_to and the Courier has_many of. The following lines are per the document instructions of my course:
#cour_id=params[:shipment][:courier_id]
#courier=Courier.find(#cour_id)
#shipment=Shipment.new(params.require(:shipment).permit(:tracking_number, :shipment_date))
#shipment.courier<< #courier
#shipment.save
redirect_to shipment_path(#shipment)
#shipment=Shipment.new(shipment_new_path)
if #shipment.save
redirect_to(:controller=>'shipment' ,:action=>'index')
else
render('new')
end
end
The associations appears to be necessary because one of the forms at the shipment/new.erb.html is a drop down of a set of Courier records from one of it's table columns. Which appears to display from that form within that page.
The issue I come across is in the line '#shipment.courier << #courier', the '<<' is treated as an undefined method for nil:NilClass. I have tried variations of this line of code (#shipment.couriers..., #shipment.courier.id...), but it doesn't seem to make a difference.
screencap of the error
I suspect that a more pressing problem is at play from this particular table, I noticed that even from the back end, the table wouldn't appear to save new records. Even though there is nothing particularly different from this table compared to others. I have initially attributed it's inability to pass data as due to a misalignment between table associations, now I interpret it as an issue of not being able to function without adequately being connected to the id of the Courier table.
The question stands, how do I get the associations to function?
This is really just a standard run-of-the-mill nested resource that you're describing. I really don't know what to make of the jumble of code in your question - but the Rails way of doing this would be:
resources :couriers do
resources :shipments,
only: [:index, :new, :create]
end
class ShipmentsController < ApplicationController
# use callbacks to avoid repitition
before_action :set_courier, only: [:new, :create, :index]
# GET /couriers/1/shipments
def index
#shipments = #courier.shipments
end
# GET /couriers/1/shipments/new
def new
#shipment = #courier.shipments.new
end
# POST /couriers/1/shipments
def create
#shipment = #courier.shipments.new(shipment_params)
if #shipment.save
# shorthand for courier_shipments_path(#courier)
redirect_to([#courier, :shipments])
else
render(:new)
end
end
private
# use a private method instead of repeating yourself
def shipment_params
params.require(:shipment)
.permit(:tracking_number, :shipment_date)
end
def set_courier
#courier = Courier.find(params[:courier_id])
end
end
# app/views/shipments/new.html.erb
<%= form_with(model: [#courier, #shipment]) do |f| %>
<div class="field">
<%= f.label :tracking_number %>
<%= f.text_field :tracking_number %>
</div>
<div class="field">
<%= f.label :delivery_date %>
<%= f.date_field :delivery_date %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>

Form sending me to the wrong controller despite correct URL in a Rails app

I have the following routes defined:
App/config/routes.rb
resources :pools do
resources :match_predictions, path: "predictions", as: "predictions", only:[:index, :create, :update]
post "predictions/season" => "season_predictions#create"
patch "predictions/season" => "season_predictions#update"
put "predictions/season" => "season_predictions#update
end
Which result in the following paths/Url/controller#action (omitting pool resources routes for simplicity):
pool_predictions GET /pools/:pool_id/predictions(.:format) match_predictions#index
POST /pools/:pool_id/predictions(.:format) match_predictions#create
pool_prediction PATCH /pools/:pool_id/predictions/:id(.:format) match_predictions#update
PUT /pools/:pool_id/predictions/:id(.:format) match_predictions#update
pool_predictions_season POST /pools/:pool_id/predictions/season(.:format) season_predictions#create
PATCH /pools/:pool_id/predictions/season(.:format) season_predictions#update
PUT /pools/:pool_id/predictions/season(.:format) season_predictions#update
As context: I have three models Pool, MatchPrediction, SeasonPrediction. Each #pool is a sports tipping competition that has_many #match_predictions and has_one #season_prediction. The key view in my app is where the user posts/updates his predictions. As most of it is #match_predictions, I'm using match_predictions#index & match_predictions/index.html.erb to control/display this view. This view is accessed via:
/pool/:pool_id/predictions
The problem: I have a form to create/update #season_prediction that lives within the realms of the match_predictions resource. In order to preserve error messages, in the event of objects failing to be saved, I'm rendering match_predictions/index.html.erb after failure of the update/create actions at the season_predictions_controller. This works well with the default routes, say if I do:
resources :pools do
resources :match_predictions, path: "predictions", as: "predictions", only:[:index, :create, :update]
resources :season_predictions
end
This has, however, the unintended consequence of modifying the location path to something like:
/pool/:pool_id/season_predictions/:id
I think this can be confusing for the user as he is still in the same view while the URL has changed drastically. Plus the :id at the end of the URL doesn't make any sense as the user can only have one season prediction per pool.
Hence with this approach I wanted to achieve
The URL after action failure must be as similar as possible to the original /pool/:pool_id/match_predictions.
Remove the :id at the end of the URL, that belongs to the #season_prediction.
Use the same form to either create or update #season_prediction depending if I'm serving a new instance or a
previously saved instance form the controller.
So far I've a form like:
<%= simple_form_for([#pool, #season_prediction], url: pool_predictions_season_path) do |f| %>
<div class="form-inputs">
<%= f.input :champion %>
<%= f.input :second_place %>
<%= f.input :third_place %>
<%= f.input :last_place %>
<%= f.association :pool_participant %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
Although the rendered HTML form sets the correct action path to: action="/pools/1/predictions/season" upon submission it sends the request to match_predictions#update which I don't get exactly why as there's no involvement of the that controller.
Could you please help me understand why and achieve the expected outcome?
So it seems that when setting routes with a slash, such as the ones between 'predictions' and 'seasons' in the following routes:
post "predictions/season" => "season_predictions#create"
patch "predictions/season" => "season_predictions#update"
put "predictions/season" => "season_predictions#update
It was interfering with Rails in such way that the season_prediction controller was ignored and the match_predictions controller was reached given the customisation of the url method as: "predictions" which coincide purposefully.
resources :match_predictions, path: "predictions", as: "predictions", only:[:index, :create, :update]
I ended up getting rid of the slash and setting the season_prediction routes as the one below:
put "predictionss" => "season_predictions#update"
Yes with double 's' at the end to differentiate from the match predictions controller routes. This doesn't feel like best practice at all. It may confuse other people when reading the code but at least the user will hardly notice the change.

How to create new text field

I know this is probably a very basic question but I am brand new to Ruby and kinda in a dead end. I have made a simple little site with profiles and profile pages. But on the profile pages I would like to add a new text field like "Bio" for instance where the user types in a bio about himself and it shows. Im just at a blank on how to create a new text field where people can input this stuff. I know this is basic stuff just stuck and looking for some help or guidance to a tutorial or something. Thank you in advance
Here's an example copied from another answer:
<%= form_for(:ad, :url => {:action => 'create'}) do |f| %>
<%= f.text_field(:name) %>
<%= f.text_area(:text, "", :size => "50x10") %>
<%= submit_tag("Submit") %>
<% end %>
This is kind of a complicated question, once you think about it, because there are so many parts.
Ruby on Rails is built on a architecture, called Model View Controller or MVC. The three parts together make the user interface that is presented to the user.
Models are the actual data, like the User objects, in this case. To create the model, type in this command to the console:
rails g model User bio:text name:string
This will make a basic user model, which only contains two columns, a column for the bio, and a column for their name. Note that this is very uncomplicated, and this can be expanded on a lot, but for now it will do.
Or, if you already have a user model, type in this command to the console:
rails g migration add_bio_to_users bio:text
Next are the controllers, controllers are, in a way, what connect the models and the views, so they manage all of the logic in the back end, like creating new users, or adding bios to their profiles.
You can create the user controller like this (if you do not already have one):
rails g controller Users new
And then, you can add this code to the new file generated, to add the functionality of adding bios (and showing them, too) (and updating other columns as well):
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
render #user
else
render #user # Handle error accordingly
end
end
def show
#user = User.find(params[:user])
end
private
def user_params
params.require(:user).permit(:name, :bio)
end
Now, to the final part, which is the view, which is the actual thing that is presented to the user:
<%= form_for(:user, :url => {:action => 'update'}) do |f| %>
<%= f.text_field(:name) %>
<%= f.text_area(:bio, "", :size => "50x50") %>
<%= f.submit yield(:button_text) %>
<% end %>
Note that this is just a simple view that assumes that you also have a column name in your User model, you can change this accordingly.
And, finally, to show the user, add this to the show view:
<%= #user.bio %>
to show the bio in the show view.
Good luck!

Rails Undefined Method Path for New

I am relatively new to rails but having a real problem with something that I know should be really simple. I have a model called channel, in it I have a simple new method, in the view I have form but every time I try and load it, I get an error to say:
undefined method `channels_path'
My view (new.html.erb) is really simple, for the minute it just has a button in it with a name and a value, it just looks like this:
<%= simple_form_for #channel do |f| %>
<%= f.error_notification %>
<%= f.button :submit, 'Free Plan', name: 'plan', value: 'free' %>
<% end %>
My Controller has:
def new
#channel = Channel.new
end
And in my routes I have:
resources :channel
Output form a rake routes is:
channel_index GET /channel(.:format) channel#index
POST /channel(.:format) channel#create
new_channel GET /channel/new(.:format) channel#new
edit_channel GET /channel/:id/edit(.:format) channel#edit
channel GET /channel/:id(.:format) channel#show
PATCH /channel/:id(.:format) channel#update
PUT /channel/:id(.:format) channel#update
DELETE /channel/:id(.:format) channel#destroy
Which all looks how I expect. But as the error says there is no channels_path, but as far as I am aware, there shouldn't be.
I am sure this is supposed to be really simple but I just cannot see what I am doing wrong. Can anybody help?
Many thanks
David
EDIT
I have updated the route to be:
resources :channels
I can now load the form, however I now get the error when trying to submit it:
param is missing or the value is empty: channel
Being caused by:
# only allow specific params
def channel_params
params.require(:channel).permit(:name,
:slug,
:description,
:plan,
:subscription_ends
)
end
I am assuming singular is correct here based on the model, but have tried plural too with no luck. Any more thoughts?
Many thanks
Edit
Got it working in the end, it appears you have to have at least one input in your form. I added an input for the name field and it started working.
Many thanks to everyone that commented
According to your rake task, the path should be
channel_path
If it's not working with the simple_form_for helper, it's probably because you should have set up your routes as resources: channels
UPDATE
The new bug is coming from nothing being received by the controller for :channel
Try adding a field like so
f.hidden_field :plan, :value => "free"

Ruby on Rails Passing Parameter In URL

This is probably a very simple fix but I've been unable to find an answer just yet.
My application has orders and tasks. Orders have many tasks. When a user clicks new task in the show order view, it passes the order.id:
<%= link_to "New Task", new_task_path(:order_id=> #order.id) %>
The url shows:
/tasks/new?order_id=1
I just don't know how to extract this and use it in my form? I have tried:
<%= f.text_field :order_id, :value => #order_id %>
But it's not working.
You can do:
<%= f.text_field :order_id, :value => params[:order_id] %>
Alternately, capture the value (with params) in the controller and assign it to #order_id there.
You are doing this wrong, which is a big deal in Rails where convention-over-configuration is such an important ideal.
If an order has many tasks, your route should look like this:
/orders/:order_id/tasks/new
And your routes should be configured thusly:
resources :orders do
resources :tasks
end
You should [almost] never find yourself passing around record ids in the query string. In fact, you should almost never find yourself using query strings at all in Rails.

Resources