Better way of getting objects id from another controller - ruby-on-rails

I have ideas controller and static_pages controller. The latter has home action which displays all ideas and which i also use as root path.
I want the user be able to Edit the displayed ideas. So far i have this:
<% if #ideas.empty? %>
<p>Share your ideas! See what people think about it.</p>
<% else %>
<% #ideas.each do |idea| %>
<div class="panel panel-default">
<div class="panel-heading"><%= idea.name %></div>
<div class="panel-body"><%= idea.description %> <br>
<%= link_to 'Edit', edit_idea_path(idea.id) %>
</div>
</div>
<% end %>
<% end %>
I had an issue with an empty idea id which i solved by adding idea.id inside edit_idea_path
Now my question is, is that the proper, Rails way of doing it? In what other way can i fetch the idea object from this index page and use it in my ideas controller instead of static_pages controller?
I tried playing around with routing, but I have very vague understanding of it despite reading the guides and others code. I'd appreciate any insight about this matter.

First you need to understand that the requirement of your project defines what you should do in the code, whithout of concerning about the proper way to do something. You just need to follow the rails conventions.
http://guides.rubyonrails.org/active_record_basics.html#convention-over-configuration-in-active-record
Now, back to your question. You just need to create an action (that will handle a view) in your ideas_controller that will manage the edition of the data sended by de static_pages_controller, i will call it (just for example) edit_static_ideas and receive the data with params:
In your ideas_controller : app/controllers/ideas_controller.rb
def edit_static_ideas
#idea = Idea.find(params[:id])
end
Then you need to create the view in your views->ideas folder. An name it, just to continue my example i'll name it edit_static_idea.html.erb. And set the load of the data you get in #idea as a form or a form_for. Then you can submit that edited data and upload it into other action.
Then you have to configure your routes file and add
config/routes.rb
get 'edit_static_idea/:id', to: 'ideas#edit_static_idea', as: 'edit_ideas'
After that, if you run "rake routes" in your console (inside your rails project), you should see your new route (yay!)
Now you have to take the path in your route and use it in you static_pages_controller's view to redirect it to the edit_idea's view handle it by ideas_controller. And be sure that you also send the id of the selected item.
app/views/static_pages/home.html.erb:
<%= link_to 'Edit Idea', insert_your_edit_idea_obtainedinrakeroutes_path(id: idea.id) %>
At last, you only need to configure the form in your edit_static_idea.html.erb and assign it an upload/save route and redirect it to the view that you want.
for example:
In your routes file: config/routes.rb
patch 'save_edited_idea', to: 'ideas#save_edited_idea', as: 'save_edited_idea'
In your ideas_controller: app/controllers/ideas_controller.rb
def save_edited_idea
#idea = Idea.find(params[:id])
respond_to do |format|
if #idea.update(idea_params)
format.html { redirect_to the_view_that_you_want_path(id: #idea.id), notice: 'Data saved without problems.' }
else
flash.now[:alert] = "error"
format.html { render :offer }
end
end
end
I didn't wanted to be so detailed, because i wanted to help you to understand what you have to do. I hope it helps :P

Related

Ruby on rails, PATCH method reverted by transaction rollback

I'm not good at ruby but I have to make a project using rails and I encountered a problem. I'm making a forum application where a user can have multiple profiles and change between them. After many hours I thought that maybe it would be easier if I added a whole column to the Users table called current_profile_id where I'd store the current chosen profile by the user. I am using the PATCH method to insert a profile id into the table but upon doing that the transaction gets rolled back and I am left with nothing. I am a total newbie and kinda don't want to do this so my code is most likely terrible.
view:
<% #user.profiles.each do |profile| %>
<%= link_to content_tag(:div, profile.name), users_profiles_path(:current_profile_id => profile.id), method: :patch %>
<% end %>
<div>
<%= current_user.current_profile_id %>
</div>
user controller:
def setProfile
#user = User.find_by(id: params[:id])
#user.current_profile_id = params[:current_profile_id]
#user.save
end
route:
patch '/users/:id/profiles', to: 'users#setProfile'
screenshot from wsl teminal
I know the idea isn't really thought through but at this point I kind of have to roll with it.
The problem isn't with your patch request per se: it's that you don't have a view template set up for the controller to forward to. Try creating view template to go with your setProfile action, or redirect the request to another location from that action.

Get rails route to reflect database lisiting

I currently have a page that searched through a listings database. On clicking a selection, the view links to that listing's show page:
<div class="listings_wrapper">
<% #listings.each do |listing| %>
<%= link_to listing_url(listing), class: "listing_link" do %>
<div class="listing">
<div class="picture">
<% if listing.thumbnail != nil %>
<%= image_tag(listing.thumbnail, class: "list_image") %>
<% end %>
</div>
The show page that is currently routed as:
get 'listings/:listing_id', to: 'listings#show', as: 'listing'
which will get me the address
localhost3000/listing/612983618 (arbitrary id)
What I'm trying to do is get the route to display information from the database in the route instead, for SEO purposes:
localhost3000/listing/[address]/[booking_id]
When I try to adjust to
get 'listings/:listing_id', to: 'listings#show', as: 'listing/:address/:booking_id'
I get blocked on loading. I've been looking around stackoverflow at similar answers, but haven't got my head around this problem as of yet. Since the link is pulling the object itself, and the route is pulling the id from that, it would make sense to refer to the :address key instead, but something is clearly missing. Help?
In order to make the URI for listings#show to receive the address and booking_id of the object, then you could move the alias in your route definition to the uri argument, like:
get 'listing/:address/:booking_id', to: 'listings#show'
Now it'll be waiting both attributes. While in your controller if you want to find that specific object from both sent attributes, then you can use find_by:
#listing = Listing.find_by(adress: params[:address], booking_id: params[:booking_id])
#listings = Listing.last(3)
Note this will work, but in case you have more than one record with same address and booking_id, find_by will just return the first one.

pass value of td element to rails controller

I'm trying to pass the value of a element to a rails controller!
Currently, I have something like this:
<td id="dbname"><%= link_to db, :action => :show %></td>
This represents a row in an html table, which contains a string value, e.g. "development".
When the user clicks on the "development" link, the <%= link_to ... %> grabs the value from the current clicked and passes that to a rails controller action, in this case the show action.
How can this be achieved!?
UPDATE - generating links:
<% #dbs.each do |db| %>
<tr>
<td id="dbname"><%= link_to db, :action => :show %> </td>
</tr>
UPDATE 2:
this is my index controller:
conn = Mongo::Connection.new
#dbs = conn.database_names #this returns an array of strings (which are the names of the databases)
Now I want to be able to click on of these databases and then to pass the clicked text to the rails controller show action. I'm not sure how I would generate a custom resources path for these links... but I was contemplating of doing it using Ajax or something javascript related. Maybe get the text of clicked link using jQuery and then send an Ajax request to the rails controller with the text as a parameter!
I think that it's a strange thing what you're trying to do, but a solution could be to use javascript to append the id to the href of each link as a query string.
If you could explain a little bit what you're trying to achieve maybe we could find a better solution.
Hope it helps!
Edit:
If you have a table of links I think that you should consider them as a resource and managing them the REST way.
Your controller should have an index and show action and you should declare the links as a resource in the routes file (maybe link it's a reserved word and you will have to use a different name, I'm not sure), the index action will fetch all the links and when you render them, you could specify the link for each one with something similar to "link_path(link.id)" (remember, you should have a show action defined) in the controller you will receive the link id so you could load it with a simple "find" and pass it to the view.
I recommend you to always look for the REST way to solve a problem in ROR.
Edit 2:
Ok let's see if this works for you:
I suppose that you have a model that represent those links that you're talkin about, for example:
class DataBaseLinks < ActiveRecord:Base
end
This model with be backed up by a table in your database, if you have generated it the rails way, you will also have an id column that identify each database link.
in your controller, let's say DataBaseLinksController, you'll have:
class DataBaseLinksController < ApplicationController
def index
#dabatase_links = DataBaseLink.all
end
def show
#database_link = DataBaseLink.find(params[:id])
end
end
(I've avoided all the validations and checks).
All you have to do in your index.html.erb is:
<% #database_links.each do |database_link| %>
<%= link_to database_link.name, database_link_path(database_link.id) %>
<% end %>
This will generate all the links with the correct path to the show action (maybe the route helper is a little bit different, but not so much).
Notice also that you'll have to add into your routes.rb the following line:
resources :database_links, :only => [:index, :show]
How do you see it?
Edit 3:
(I'll delete all my edited answers when we find a correct one)
Ok I'm going to suppose that you are not using something like mongoid so you don't have active record similar objects.
Have you tried this in your view:
<% dbs.each do |dbs_name| %>
<%= link_to dbs_name, :controller => "your_controller", :action => :show, :dbs_name => dbs_name %>
<% end %>

how to connect my model to my app

Hey all,(im a beginner in rails)
i've created a controller that look like that:
class HomeController < ApplicationController
def homepage
end
def showmsg
#postword = params[:p]
end
end
the showmsg view looks like that:
<%= #postword %>
and my homepage view looks like that:
<%= form_tag( {:controller => 'home', :action => 'showmsg'}, :method => "post") do %>
<%= text_field_tag(:p,#postword) %>
<%= submit_tag("post") %>
<% end %>
now i have a form that i can write something in it and it will show on the showmsg view.
i created a model with the param :posts with a :description "text" field too.
MY QUESTION is how do i implement the model in the code so any thing i write will be in a list with the things i wrote before, because now (obviously) anything if i write something its deleting the one i wrote before.
thank you all!
I would argue that you're approach is not very rail's like... so if you're learning rails... you're learning it wrong.
Make a Model. Call it "Message":
rails generate model Message content:string
remember to migrate (hopefully you have your databases setup properly):
rake db:migrate
Then in your controller, when you post, you can create message like this:
def create #instead of showmsg... 'create' is the standard name for this
Message.create(params[:message])
#messages = Message.all
end
This will create the message in the database, and then it will get all the messages out of the database and put them into #messages.
You need to edit your form so that it uses form_for. You need to pass it #message, which is an instance of Message.new that your first controller action created. You should call this new
In your create.erb.html file, you show all the messages like this:
<ul>
<% #messages.each do |message| %>
<li><%= message.content %></li>
<% end %>
</ul>
I actually wouldn't recommend showing all the messages in the create action - it should really happen in the index action and you should redirect... but we need to keep this simple. Just google this or watch some of Ryan's screencasts and you'll get it.
And you're done. This is the "Rails Way" to do things. It's best to learn it the way they want you to learn it.
I would also commend that you format your code properly by indenting, and start naming your methods to be real english. For example, showmsg is bad and show_message is a lot better.
If all of this is totally confusing, then just create a new project, and then type:
rails generate scaffold message content:string
It will basically build the application you want and a lot more. You can just read the code and see how they did it.
Hope it helps.
Your approach is not really rails like so some tweaks and fixes are needed. Suggestions: check rails approach to REST. The following code will work it is a little more rails like, but still not all the way there.
Generate a model
rails generate model Message postword:string
this will generate the model and create the migration necessary to create the table in the database.
Create the table
rake db:migrate
Define a post action
It will save the postword in the database. In your controller:
def create
#message = Message.create!(params[:message])
if #message.save
redirect_to "/home/showmsg"
else
render :action => "/home/homepage"
end
end
Create and instance of Message to use in your form
def homepage
#message = Message.new
end
Fix your form tag
<%= form_for #message, :url => "/home/create" do |f| %>
<%= f.label :postword %>
<%= f.text_field :postword %>
<%= f.submit "Create" %>
<% end %>
Now let's show the words in the showmsg page
In the controller select the postwords from the database:
def showmsg
#postwords = Message.all
end
Showing them: /showmsg.html.erb
<H1>postwords list</H1>
<ul>
<% #postwords.each do |p| %>
<li><%= p.postword %></li>
<% end %>
</ul>
Your routes.rb file will have this routes:
get "home/homepage"
get "home/showmsg"
post "home/create"
Define an attribute :new_text in a way similar to this:
class TheModel
# Virtual writer - everything assigned to this attribute
# will be added to self.text
#
def new_text=(v)
self.text += v.to_s
end
def new_text
"" # This is write-only attribute
end
end
Now, use the field 'new_text' in your form.
Of course, this is a very simple example. You should decide whether you want to add the content on every call to :new_text=, maybe some validation would help, the read accessor may need some care, and so on.
For some good guides which may help you start, see the site http://guides.rubyonrails.org/

Can I use redirect_to in a view in RoR?

In my app, I've got a little box that appears on every page, checking on the status of requests made by the user. If a request is accepted at any time, then the user should automatically be taken to a certain page. This is my code so far:
<% offersMade.each do |w| %>
<% if w.accepted == true %>
<% redirect_to offer_path(:email => "email#gmail.com") %>
<% end %>
<% end %>
But I'm getting this error:
undefined method `redirect_to' for #<ActionView::Base:0x1042a9770>
Is it not possible to user redirect_to in a view? If not, is there something else I can use? Thanks for reading.
redirect_to is a method of ActionController::Base Class so you can not use it in ActionView.
You can try following
<% if w.accepted == true %>
<script type="text/javascript">
window.location.href="/logins/sign_up" // put your correct path in a string here
</script>
<% end %>
Edited for the email parameter
window.location.href="/logins/sign_up?email=<%= w.email %>"
Sorry i don't know if there is anything in ruby for that.
If you want to use redirect_to from view , do this method:
syntax : <%controller.redirect_to path %>
Example:<% controller.redirect_to users_profile_path %>
The code in the view could be moved into the controller which would make redirect_to available.
class ApplicationController < ActionController::Base
before_action :check_for_accepted_offer
def check_for_accepted_offer
if Offer.any? { |o| o.accepted }
redirect_to offer_path(:email => "email#gmail.com")
end
end
end
If the OP wanted to immediately change the URL when an offer is accepted then none of the Ruby code shown in the answers would help because it is only evaluated when the page is loaded. The OP would need to setup some kind of polling or push strategy to alert the browser when an offer has been accepted and then use the JavaScript redirect scheme posted in another answer:
window.location.href="/logins/sign_up?email=<%= w.email %>"
Although, this does not answer the question: "How can I use redirect_to in a view", I think this answer would ultimately have been more useful to the OP. I stumbled across someone using this answer to redirect to another page, when the redirect should have been performed in the controller.
redirect_to is not a method of ActionView. Its a method of ActionController. You can probably use Javascript window.location.href on page load or some other event to take your user to another page.
Yes, you can call controller.redirect_to from your view to get what you want without having to render the whole response and then use javascript on the client to make a new request.
In your example, this would look like:
<% offersMade.each do |w| %>
<% if w.accepted == true %>
<% controller.redirect_to offer_path(:email => "email#gmail.com") %>
<% end %>
<% end %>
Note that this controller.redirect_to will not break out of your loop, so you will probably want to break, and you'll probably want to make sure that the rest of your view is only conditionally rendered if you didn't redirect.
(Disclaimer: I don't necessarily condone this technique. You would be better off doing this in your controller or helper, as others have mentioned.)

Resources