Newbie rails database relation question - ruby-on-rails

I have two models Station and Broadcast. Broadcast belongs_to Station and has a station_id column.
I don't know how to make new method in BroadcastController to expect the station_id value and how to create a new Broadcast with right station_id in it.

I'd recommend against using a link_to here. Using a 'get' action to change/add data on the server is generally frowned upon. Also, I wouldn't use the 'new' action, as it's used by convention in a Rails Restful route to present a form, not actually persist data. All that said, the simple answer to your question is to pass a value through the link_to helper like so:
link_to 'Add broadcast', new_broadcast_path(:station_id => station.id)
...and your 'new' method on BroadcastsController would do:
def new
#broadcast = BroadCast.new(:station_id => params[:station_id])
if #broadcast.save
flash[:notice] = "New broadcast created!"
redirect :back # or whatever
else
# etc.
end
end
But, again, this is not the right way to do this. What you probably want to do is stay within the Rails (and web) conventions and use a form to create the new broadcast record by way of the 'create' action on the controller. You might place this form next to your stations on the index view which presents a button that points to the correct 'create' action of BroadcastsController, and uses a hidden_field to set the station_id. Something like (EDIT: better use of hidden_field):
<% form_for :broadcast do |f| %>
<%= f.hidden_field :station_id, :value=> station.id %>
<%= submit_tag 'Add broadcast' %>
<% end %>
Assuming you've set a restful route in routes.rb for broadcast like:
map.resources :broadcasts
...then your form will automatically point to a 'create' action on BroadcastsController, which you should write to look something like:
def create
#broadcast = BroadCast.new(params[:broadcast])
if #broadcast.save
# etc., etc.
end
The Rails Guides are a good place to get more comfortable with the Rails controller actions. I'd also spend some time looking over the RESTful actions and how they're used in Rails as well.

You actually do specify a station_id for your Broadcast model, such as
script/generate scaffold broadcast name:string station_id:integer ...
so when you add a broadcast record, it will ask you for a station_id.

Related

Rails 4 Link_ to Create New Record - Request Type

I am on Rails 4.
Just created a Favorite model & controller in which users can favorite articles. I have it set up so when a user clicks on the link, it routes to the favorite action inside of the favorites_controller. Right now, it is a get request, and inside of the action it is simply creating a new favorite.
My question is... is it ok that this is a get request? I feel like maybe a post request would be better (as forms use post to create things), but since there is no form in this case I decided a get request would be fine. Is this ok? or frowned upon?
here is the link_to in my view:
<%= link_to favorite_path(title: #article.title, id: #article.id) do %>
<span class="glyphicon glyphicon-star-empty"></span>
<% end %>
and the action it routes to in the controller:
def favorite
current_user.favorites.create(article_id: params[:id],
article_title: params[:title])
flash[:success] = "You added this page to your favorites."
redirect_to request.referrer || root_url
end
and my routes.rb:
get 'favorite' => 'favorites#favorite'
Everything works fine, just want some clarification as to the get request and if this is the best way to achieve what I am doing. If there is already documentation on this, please send it my way.
No, you shouldn't use a get request to create things or change states.
The reason is simple: Searchengines will follow links and trigger that action. Or some browsers may preload links to speed things up. In both case you will create records although the user never chose to click the link.
Instead just tell Rails to use some javascript to fake a post request (note the method: :post part):
<%= link_to(favorite_path(title: #article.title, id: #article.id),
method: :post) do %>
<span class="glyphicon glyphicon-star-empty"></span>
<% end %>
Read the doc about link_to for details.

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

Rails Forms for custom actions

I'm trying to link the input of a form to a specific action in my rails app.
Currently if I go to www.myapp.com/check/:idNumber, I'll be able to trigger the action just fine (which means routes is setup properly?). This action is basically a function call to a ruby/rails script with the parameter "idNumber" being passed to it. If the function is successful, it would return a newly created "Person" object and nil otherwise. This is different than the standard new operation as it determines the the attributes based on some information that it obtained from a database somewhere else.
Rake routes does give me the following:
check /check/:idNumber(.:format) person#check {:id=>/\d+/}
What I'm having trouble implementing is the form itself.
<%= form_tag("/check", :method => "get") do %>
<%= text_field_tag(:idNumber) %>
<% end %>
Controller action:
def check
regCheck = RegCheck.new
#person = regCheck.check_id(params[:idNumber])
if #person.name == nil
redirect_to root_path
end
end
submitting the form above would bring me to myapp.com/check?utf8=✓&idNumber=1234 instead. Can someone tell me what am I doing wrong?
I believe that using the check_path helper that is generated from the routes file is your best bet.
The form should look like this then.
<%= form_tag(check_path) do %>
<%= text_field_tag(:idNumber) %>
<% end %>
Rails forms can be finicky, especially when trying to build really customized forms.
This line
= form_for [#object]
Determines where the form goes, as well as the object that is being implemented. If you want to route the form to a different place, you can user the :url option. This options determines the path of the form, however you must keep in mind that the method is determined by the #object. If it is a new object, the method will be POST, an existing object will use a PUT method.
Let's suppose you want to update an existing object, but you want to send in data for a new object belonging to the existing object. That would look like
= form_for [#object], :as => #child_object, :url => my_optional_custom_path do |f|
# etc...
This generates a form sending a PUT request to the custom url (or the update path for #object if no custom url is supplied. The PUT request is sent with the parameter params[:child_object].
Hopefully this helps!
Best,
-Brian
I don't think it's possible the way you're trying.. The URL for the form is created before the user inputs any data.. So you need to remove the :idNumber from your routing..
If you do you get the following route:
check /check(.:format) person#check
Because the regex is removed now, you need to do this in you're controller:
def check
# Make sure ID is digits only
idNumber = params[:idNumber].gsub(/[^\d]/, '')
regCheck = RegCheck.new
#person = regCheck.check_id(idNumber)
if #person.name == nil
redirect_to root_path
end
end
You're form is allright, but you may want to use check_path like TheBinaryhood suggests..
If you really want it to be check/:idNumber you may also be able to submit the form to another action and redirect it to the right path from there..

How do I force Rails to use the superclass name in link_to helpers when using STI?

I'm using STI with a Rails 3.2 app. I want to force Rails to use the superclass name in link_to helpers (or any where else when it's generating paths) and not the subclass name.
So, <%= link_to current_user.name, current_user %> produces /:class_name/:id (class name can be "Moderator," "Member," etc...).
I would like it to produce /users/:id, where users does not change to the name of the subclass. I know I can change current_user to user_path(current_user), but I prefer to use the shortcut, letting Rails figure it out.
Is this possible?
I think you should define url helpers, something like this
def moderator_url record
user_url record
end
Or just use aliases
alias :moderator_url :user_url
This is code which rails use for url generation when you pass a record as a option
https://github.com/rails/rails/blob/537ede912895d421b24acfcbc86daf08f8f22157/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb#L90
Use the named route:
<%= link_to current_user.name, user_path(current_user) %>
For links, I can get around this by adding a resource:
resources :owners, path: 'users', controller: 'users'
For forms, I need to specify generic form. My initial form was
= simple_form_for #user do |f|
To make this work, I had to specify the path and the method, while using a generic name instead of passing the user object to the form directly:
= simple_form_for :user, url: user_path(#user) do |f|

Create a link to a defined method?

As my first Rails app, I'm trying to put together a simple blog application where users can vote on posts. I generated the Blogpost scaffold with a integer column (entitled "upvote") for keeping track of the vote count.
In the Blogpost model, I created a function:
def self.voteup
blogpost.upvote += 1
end
On the Blogpost index view, I'd like to create a link that does something like:
link_to "Vote up" self.voteup
But this doesn't seem to work. Is it possible to create a link to a method? If not, can you point me in the right direction to accomplish this?
What you are trying to do goes against the MVC design principles. You should do the upvoting inside a controller action. You should probably create a controller action called upvote. And pass in the post id to it. Inside the controller action you can retrive the post with the passed in ID and upvote it.
if you need serious voting in your rails app you can take a look at these gems
I assume that you need to increment upvote column in blogspots table. Redirection to a method is controllers job and we can give links to controller methods only. You can create a method in Blogposts controller like this:
def upvote_blog
blogpost = Blogpost.find(params[:id])
blogpost.upvote += 1
blogpost.save
redirect_to blogpost_path
end
In your index page,
<% #blogposts.each do |blogpost| %>
...
<%= link_to "Vote up", :action => upvote_blog, :id => blogpost.id %>
...
<% end %>
You can not map Model method to link_to in view. you can create an action in controller to access the Model method and map it using link_to, also if the action is other than CRUD, then you should define a route for the same in route.rb

Resources